
关于
惯用 Kotlin 模式、最佳实践和编码规范,用于构建健壮、高效且易维护的 Kotlin 应用,涵盖协程、空安全和 DSL 构建器。
name: kotlin-patterns description: 惯用 Kotlin 模式、最佳实践和约定,用于构建健壮、高效和可维护的 Kotlin 应用程序,包括协程、空安全和 DSL 构建器。 origin: ECC
Kotlin 开发模式
惯用 Kotlin 模式和最佳实践,用于构建健壮、高效和可维护的应用程序。
何时使用
- 编写新的 Kotlin 代码
- 审查 Kotlin 代码
- 重构现有 Kotlin 代码
- 设计 Kotlin 模块或库
- 配置 Gradle Kotlin DSL 构建
工作原理
此技能在七个关键领域强制执行惯用 Kotlin 约定:使用类型系统和安全调用运算符的空安全、通过 val 和数据类的 copy() 实现不可变性、使用密封类和接口实现穷举类型层次结构、使用协程和 Flow 的结构化并发、使用扩展函数在不继承的情况下添加行为、使用 @DslMarker 和 lambda 接收者的类型安全 DSL 构建器,以及用于构建配置的 Gradle Kotlin DSL。
示例
使用 Elvis 运算符的空安全:
fun getUserEmail(userId: String): String {
val user = userRepository.findById(userId)
return user?.email ?: "unknown@example.com"
}
用于穷举结果的密封类:
sealed class Result<out T> {
data class Success<T>(val data: T) : Result<T>()
data class Failure(val error: AppError) : Result<Nothing>()
data object Loading : Result<Nothing>()
}
使用 async/await 的结构化并发:
suspend fun fetchUserWithPosts(userId: String): UserProfile =
coroutineScope {
val user = async { userService.getUser(userId) }
val posts = async { postService.getUserPosts(userId) }
UserProfile(user = user.await(), posts = posts.await())
}
核心原则
1. 空安全
Kotlin 的类型系统区分可空和非空类型。充分利用它。
// Good: Use non-nullable types by default
fun getUser(id: String): User {
return userRepository.findById(id)
?: throw UserNotFoundException("User $id not found")
}
// Good: Safe calls and Elvis operator
fun getUserEmail(userId: String): String {
val user = userRepository.findById(userId)
return user?.email ?: "unknown@example.com"
}
// Bad: Force-unwrapping nullable types
fun getUserEmail(userId: String): String {
val user = userRepository.findById(userId)
return user!!.email // Throws NPE if null
}
2. 默认不可变
优先使用 val 而非 var,不可变集合而非可变集合。
// Good: Immutable data
data class User(
val id: String,
val name: String,
val email: String,
)
// Good: Transform with copy()
fun updateEmail(user: User, newEmail: String): User =
user.copy(email = newEmail)
// Good: Immutable collections
val users: List<User> = listOf(user1, user2)
val filtered = users.filter { it.email.isNotBlank() }
// Bad: Mutable state
var currentUser: User? = null // Avoid mutable global state
val mutableUsers = mutableListOf<User>() // Avoid unless truly needed
3. 表达式体和单表达式函数
使用表达式体编写简洁、可读的函数。
// Good: Expression body
fun isAdult(age: Int): Boolean = age >= 18
fun formatFullName(first: String, last: String): String =
"$first $last".trim()
fun User.displayName(): String =
name.ifBlank { email.substringBefore('@') }
// Good: When as expression
fun statusMessage(code: Int): String = when (code) {
200 -> "OK"
404 -> "Not Found"
500 -> "Internal Server Error"
else -> "Unknown status: $code"
}
// Bad: Unnecessary block body
fun isAdult(age: Int): Boolean {
return age >= 18
}
4. 数据类用于值对象
对主要持有数据的类型使用数据类。
// Good: Data class with copy, equals, hashCode, toString
data class CreateUserRequest(
val name: String,
val email: String,
val role: Role = Role.USER,
)
// Good: Value class for type safety (zero overhead at runtime)
@JvmInline
value class UserId(val value: String) {
init {
require(value.isNotBlank()) { "UserId cannot be blank" }
}
}
@JvmInline
value class Email(val value: String) {
init {
require('@' in value) { "Invalid email: $value" }
}
}
fun getUser(id: UserId): User = userRepository.findById(id)
密封类和接口
建模受限层次结构
// Good: Sealed class for exhaustive when
sealed class Result<out T> {
data class Success<T>(val data: T) : Result<T>()
data class Failure(val error: AppError) : Result<Nothing>()
data object Loading : Result<Nothing>()
}
fun <T> Result<T>.getOrNull(): T? = when (this) {
is Result.Success -> data
is Result.Failure -> null
is Result.Loading -> null
}
fun <T> Result<T>.getOrThrow(): T = when (this) {
is Result.Success -> data
is Result.Failure -> throw error.toException()
is Result.Loading -> throw IllegalStateException("Still loading")
}
兼容工具
Claude CodeCursor
标签
移动端
