Kotlin编程技能
概述
Kotlin是JVM上的现代编程语言,融合了函数式编程和面向对象编程的优势,提供了更简洁、安全的语法。Kotlin与Java的互操作性使其成为现代Android开发和后端开发的首选。不当的使用可能导致代码混乱、性能问题、互操作性问题。
核心原则: 好的Kotlin代码应该简洁优雅、类型安全、null安全、性能良好。坏的Kotlin代码会过度函数式、性能损耗、互操作性差。
何时使用
始终:
- Kotlin项目代码审查
- Android应用开发
- 函数式编程应用
- 协程和结构化并发
- 互操作性审查
- 性能优化
触发短语:
- "Kotlin最佳实践"
- "协程使用规范"
- "扩展函数应用"
- "DSL设计"
- "Kotlin性能优化"
- "Java互操作性"
Kotlin编程技能功能
基础特性
- 变量和常量声明
- 函数和Lambda
- 类和对象
- 接口和继承
- 数据类和密封类
Null安全
- 可空类型和非空类型
- Elvis操作符
- 安全调用操作符
- 非空断言
- 函数契约
集合和序列
- List, Set, Map操作
- 不可变集合
- 序列和流处理
- 高阶函数链
- 集合扩展函数
函数式编程
- Lambda表达式
- 高阶函数
- 扩展函数
- 作用域函数(let, apply, run, with, also)
- 函数组合
协程和并发
- 协程基础和suspend
- launch和async
- 通道(Channel)
- 流(Flow)
- 结构化并发
面向对象特性
- 继承和实现
- 属性委托
- 对象表达式
- 方法重写
- super调用
常见问题
Null安全问题
问题: 不当使用非空断言
原因: 草率使用!!操作符
解决: 优先使用安全调用?、Elvis操作符?:或let块
问题: 集合中可能包含null
原因: 没有区分List和List<String?>
解决: 明确区分可空元素,避免混淆
性能问题
问题: 过度使用扩展函数链
原因: 每次链式调用都产生新的对象
解决: 对大规模数据使用Sequence而不是Iterable
问题: 协程滥用
原因: 为简单操作创建过多协程
解决: 合理评估协程的必要性
互操作性问题
- 问题: Java调用Kotlin函数报空指针
- 原因: Java没有理解Kotlin的非空注解
- 解决: 使用@NotNull/@Nullable注解明确标注
代码示例
Null安全
// 非空和可空类型
fun nullSafetyDemo(name: String?, age: Int?) {
// 安全调用操作符
val length = name?.length // 如果name为null,返回null
println(length) // null或Int
// Elvis操作符
val safeName = name ?: "Unknown"
val safeAge = age ?: 0
println("$safeName is $safeAge years old")
// let块(只在非null时执行)
name?.let { validName ->
println("Name is $validName")
}
// 多个null检查
if (name != null && age != null && age > 0) {
println("$name is $age years old")
}
}
// 不可空和可空参数混合
fun processUser(name: String, email: String?) {
email?.let { validEmail ->
println("Email: $validEmail")
} ?: run {
println("No email provided")
}
}
// 函数返回类型建议null可能性
fun findUserById(id: Int): User? {
return if (id > 0) User(id, "John") else null
}
函数式编程和作用域函数
data class Person(val name: String, var age: Int, var email: String?)
fun functionProgrammingDemo() {
val person = Person("Alice", 30, null)
// apply - 初始化对象
val result = person.apply {
age = 31
email = "alice@example.com"
}
// let - 转换
val description = person.let {
"Name: ${it.name}, Age: ${it.age}"
}
// run - 执行代码块并返回结果
val ageGroup = person.run {
when (age) {
in 0..18 -> "Minor"
in 19..65 -> "Adult"
else -> "Senior"
}
}
// with - 执行代码块,不返回
with(person) {
println("$name is $age years old")
println("Email: $email")
}
// also - 执行代码块,返回原对象
person.also { p ->
println("Processing person: $p")
}
}
// 集合操作
fun collectionOperationsDemo() {
val numbers = listOf(1, 2, 3, 4, 5)
// 链式操作
val result = numbers
.filter { it > 2 }
.map { it * it }
.fold(0) { acc, value -> acc + value }
// 使用Sequence减少中间对象
val largeList = (1..1000000).toList()
val seqResult = largeList.asSequence()
.filter { it % 2 == 0 }
.map { it * 2 }
.take(10)
.toList()
// 高阶函数
val doubled = numbers.map { it * 2 }
val adults = listOf(
Person("Alice", 30, "alice@example.com"),
Person("Bob", 25, "bob@example.com"),
Person("Charlie", 17, null)
).filter { it.age >= 18 }
}
数据类和密封类
// 数据类 - 自动生成equals, hashCode, toString, copy
data class User(val id: Int, val name: String, val email: String)
// 密封类 - 限制继承
sealed class Result<out T> {
data class Success<T>(val value: T) : Result<T>()
data class Error(val exception: Exception) : Result<Nothing>()
object Loading : Result<Nothing>()
}
fun handleResult(result: Result<String>) {
when (result) { // 穷举所有情况,编译器检查
is Result.Success -> println("Value: ${result.value}")
is Result.Error -> println("Error: ${result.exception.message}")
is Result.Loading -> println("Loading...")
}
}
// 使用示例
fun dataClassDemo() {
val user1 = User(1, "Alice", "alice@example.com")
val user2 = user1.copy(id = 2) // 复制并修改
println(user1 == user2) // false (id不同)
println(user1) // 自动生成的toString
}
协程示例
import kotlinx.coroutines.*
class CoroutineDemo {
// 简单协程
fun launchExample() {
GlobalScope.launch {
println("Starting long running task")
delay(2000) // 不会阻止线程
println("Task completed")
}
}
// async获取结果
suspend fun fetchDataAsync(): String {
return withContext(Dispatchers.IO) {
delay(1000)
"Data from network"
}
}
// 组织多个异步操作
suspend fun parallelOperations() {
val deferred1 = async { fetchData1() }
val deferred2 = async { fetchData2() }
val result1 = deferred1.await()
val result2 = deferred2.await()
println("Result1: $result1, Result2: $result2")
}
// Flow - 响应式流
fun produceNumbers(): Flow<Int> {
return flow {
for (i in 1..5) {
delay(100)
emit(i)
}
}
}
suspend fun flowExample() {
produceNumbers()
.map { it * 2 }
.collect { value ->
println("Received: $value")
}
}
suspend fun fetchData1(): String = withContext(Dispatchers.IO) {
delay(100)
"Data1"
}
suspend fun fetchData2(): String = withContext(Dispatchers.IO) {
delay(100)
"Data2"
}
}
扩展函数和DSL
// 扩展函数
fun String.isEmailValid(): Boolean {
return this.contains("@") && this.contains(".")
}
fun <T> List<T>.middle(): T? {
return if (isEmpty()) null else this[size / 2]
}
// DSL构建器
data class HtmlElement(
val tag: String,
val attributes: MutableMap<String, String> = mutableMapOf(),
val children: MutableList<HtmlElement> = mutableListOf()
)
class HtmlBuilder {
private val elements = mutableListOf<HtmlElement>()
fun div(init: HtmlBuilder.() -> Unit): HtmlElement {
val builder = HtmlBuilder()
builder.init()
return HtmlElement("div").apply {
children.addAll(builder.elements)
}
}
fun p(text: String) {
elements.add(HtmlElement("p").apply {
children.add(HtmlElement("text:" + text))
})
}
}
fun html(init: HtmlBuilder.() -> Unit): HtmlElement {
val builder = HtmlBuilder()
builder.init()
return HtmlElement("html").apply {
children.addAll(builder.elements)
}
}
// 使用DSL
fun dslExample() {
val email = "user@example.com"
println(email.isEmailValid())
val numbers = listOf(1, 2, 3, 4, 5)
println(numbers.middle()) // 3
val document = html {
p("Hello")
p("World")
}
}
Java互操作性
// Kotlin调用Java
import java.io.File
fun javaInteropsDemo() {
val lines = File("data.txt").readLines() // List<String>?
// Kotlin处理Java返回的可能为null的集合
val firstLine = lines?.firstOrNull() ?: "No data"
}
// 为Java提供接口的Kotlin代码
fun getStringSupplier(): () -> String {
return { "Hello from Kotlin" }
}
// Platform types转换为显式类型
@JvmName("processItems")
fun process(items: List<String>) {
items.forEach { println(it) }
}