每个Kotlin开发者应该掌握的最佳实践,第一趴

Kotlin 如今已经成为了安卓开发的首选语言,并且在服务器端、桌面应用以及多平台项目中也得到了广泛应用。它简洁的语法、强大的类型系统以及与 Java 的互操作性使其成为一个强大的工具。然而,编写 Kotlin 代码不仅仅关乎语法------还关乎采用那些能够打造出更简洁、更安全且更易于维护的应用程序的最佳实践方法。

在本文中,我们将涵盖每一位开发者都应该了解的 Kotlin 核心最佳实践方法。

本文并非一份系统性的编程教程,而是我多年来编写 Kotlin 代码的一些经验总结。可能你和我会有不同的感受,毕竟每个人踩过的坑不一样,走的路也不尽相同,权当是一位 Kotlin 开发者的心得闲谈吧。

优先使用 val

不可变性可减少错误并使代码更具可预测性。

默认使用 val,仅当变量确实需要重新赋值时才使用 var

Kotlin 复制代码
val userName = "John" // immutable
var age = 25          // mutable (use sparingly)

我阅读过很多代码,发现对这个并不是很敏感。使用 val 有一个特别大的好处就是,当你第一次阅读到这个变量的时候,后续的值是只读的,不可以再赋值,在阅读源码的时候能够极大地减轻阅读负担。

例如以下代码,使用 val 优化会非常清晰:

Kotlin 复制代码
var result = 0

if (a > b) {
    result = 1
} else {
    result = -1
}

优化后:

Kotlin 复制代码
val result = if (a > b) {
    1
} else {
    -1
}

正如我所说的那样,当我看到 val result 时,我就知道它的值在初始化后不会再被修改,这在阅读源码时能极大减轻认知负担。

更聪明地使用空安全

Kotlin 最强大的特性之一就是空安全。除非某个值确实可以为空,否则应始终优先使用非空类型。使用安全调用操作符 ?. 和 Elvis 操作符 ?: 来妥善处理可为空的值。

Kotlin 复制代码
val email: String? = getUserEmail()
println(email ?: "No email provided")

除非你绝对确定某个值不为空,否则应避免强制解包------!!

哦,对了,别忘了 String? 有个 orEmpty 扩展:

Kotlin 复制代码
val email: String? = getUserEmail()
setEmail(email.orEmpty())

使用数据类

对于 POJO ,优先使用使用数据类,因为数据类会自动生成 equals()hashCode()toString()copy() 方法。

Kotlin 复制代码
data class User(val id: Int, val name: String)

这会使你的代码更加简洁,并减少样板代码。

Java 中有一个 lombok 库提供类似的功能,但是无论如何,原生支持都比第三方支持来的更加稳定,对于开发者来讲也不需要有额外的三方库学习成本。

扩展函数优于工具函数(xxxUtils)

与其用杂乱的工具方法(xxxUtils),不如使用扩展函数以一种简洁的方式添加功能。

当然,最关键的是,扩展函数能够被编译器的提示所支持,而工具函数则需要提前阅读工具类文档。

Kotlin 复制代码
// 传统的工具函数方式
fun capitalizeFirst(input:String): String {
        return input.replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() }
}

// 新的扩展函数方式
fun String.capitalizeFirst(): String =
    replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() }
    
println("kotlin".capitalizeFirst()) // Output: Kotlin

拥抱 when 表达式

when 表达式比一长串 if-else 语句更强大、更易读。

Kotlin 复制代码
val status = xxxxxx
val message = when (status) {
    200 -> "Success"
    404 -> "Not Found"
    in 500..599 -> "Server Error"
    else -> "Unknown"
}

如果配合 sealed class/interface 去使用,when 表达式会更加安全,因为它是穷尽的------你必须处理每一个可能的分支。

Kotlin 复制代码
sealed interface Bird {
    data object Sparrow : Bird
    data object Eagle : Bird
    data class Parrot(val name: String) : Bird
}

fun main() {
    val bird: Bird = xxxxxxx
    when(bird) {
        Bird.Eagle -> TODO()
        is Bird.Parrot -> TODO()
        Bird.Sparrow -> TODO()
    }
}

使用协程进行异步

与回调或 RxJava 不同,Kotlin 协程提供了一种结构化且简洁的方式来处理并发:

Kotlin 复制代码
suspend fun fetchData() {
    withContext(Dispatchers.IO) {
        val response = api.getData()
        println(response)
    }
}

始终正确使用协程作用域(例如,在 Android 中使用 viewModelScope)以避免泄漏。

优先选择密封类进行状态处理

密封类非常适合表示有限的结构,比如 API 状态:

Kotlin 复制代码
sealed class Result {
    data class Success(val data: String) : Result()
    data class Error(val exception: Exception) : Result()
    object Loading : Result()
}

当与 when 表达式一起使用时,这会使状态处理更安全、更全面(上面已经提到过了)。

正确使用作用域函数

Kotlin 提供了很多作用域函数,以便更简洁地操作对象:

  • let:多用于空值检查或转换。
  • apply:多用于初始化对象。
  • run:多在需要使用对象上下文并返回一个值时使用。
  • also:多用于执行额外的操作(如日志记录)。
  • with:多用于在不需要返回值时。
Kotlin 复制代码
val user = User(1, "John").apply {
    setEmail(xxxx)
    setPhone(xxxxx)
}

val books = mutableListOf<Book>().apply {
    add(Book("Tian", author = "Josh"))
    add(Book("ClearLove", author = "EDG"))
}

地道的 Kotlin

Kotlin 并非 Java。在 Kotlin 中应避免编写 Java 风格的代码。例如:

❗ Java 风味

Kotlin 复制代码
if (list.size > 0) { ... }

✅ 地道的 Kotlin

Kotlin 复制代码
if (list.isNotEmpty()) { ... }

注意,这里并不是争论谁好谁坏,只是 Kotlin 拥有更好的表达力。

常量代替魔法值

不要使用魔法数字或硬编码字符串------在伴生对象或对象声明中使用常量:

Kotlin 复制代码
class ApiConfig {
    companion object {
        const val BASE_URL = "https://api.example.com"
    }
}

保持函数简短且功能集中

一个函数应该把一件事情做好。将大型函数拆分成更小的、可测试的单元。这样可以提高代码的可读性和可测试性:

❌ 反面示例:职责混乱

Kotlin 复制代码
fun processWordsAndPrint(words: List<String>, minLen: Int): String {
    val result = mutableListOf<String>()
    for (word in words) {
        if (word.length > minLen) {
            result.add(word.uppercase())
        }
    }
    return result.joinToString()
}

✅ 正面示例:单一职责

Kotlin 复制代码
// 过滤出长度大于 minLen 的字符串
fun filterLongWords(words: List<String>, minLen: Int): List<String> {
    return words.filter { it.length > minLen }
}

// 将字符串列表转为大写
fun toUppercase(words: List<String>): List<String> {
    return words.map { it.uppercase() }
}

一致的命名和格式规范

遵循 Kotlin 风格指南:

  • 函数和变量使用驼峰式命名法(camelCase)。
  • 类和对象使用帕斯卡命名法(PascalCase)。
  • 保持合理的行长度。

一致性有助于团队轻松阅读和维护代码,也更具有 Kotlin 风味。

总结

Kotlin 以其富有表现力的语法和强大的功能赋予开发者能力,但编写优秀的 Kotlin 代码需要遵循最佳实践。

通过采用不可变性、空安全性、惯用结构、协程以及恰当的设计模式,你可以编写干净、安全且面向未来的代码。

无论你是在开发安卓应用、后端服务还是多平台项目,这些最佳实践都将帮助你成为一名更高效的 Kotlin 开发者。

相关推荐
FunnySaltyFish4 小时前
什么?Compose 把 GapBuffer 换成了 LinkBuffer?
算法·kotlin·android jetpack
Kapaseker10 小时前
Compose 进阶—巧用 GraphicsLayer
android·kotlin
Kapaseker1 天前
实战 Compose 中的 IntrinsicSize
android·kotlin
A0微声z3 天前
Kotlin Multiplatform (KMP) 中使用 Protobuf
kotlin
alexhilton4 天前
使用FunctionGemma进行设备端函数调用
android·kotlin·android jetpack
lhDream4 天前
Kotlin 开发者必看!JetBrains 开源 LLM 框架 Koog 快速上手指南(含示例)
kotlin
RdoZam4 天前
Android-封装基类Activity\Fragment,从0到1记录
android·kotlin
Kapaseker4 天前
研究表明,开发者对Kotlin集合的了解不到 20%
android·kotlin
糖猫猫cc5 天前
Kite:两种方式实现动态表名
java·kotlin·orm·kite
如此风景5 天前
kotlin协程学习小计
android·kotlin