标准库实践

Kotlin 标准库提供集合、字符串、范围、序列、IO、比较、时间、结果处理等基础能力。很多 Java 开发者迁移到 Kotlin 后,代码是否“像 Kotlin”,很大程度取决于是否能用好标准库。

本章不逐项翻译 API,而是整理真实项目中最常用、最容易替代 Java 样板代码的标准库实践。

集合构造

val readOnly = listOf("A", "B")
val mutable = mutableListOf("A", "B")

val set = setOf(1, 2, 3)
val map = mapOf("one" to 1, "two" to 2)

优先通过类型表达意图:

  • 返回 List<T>:调用方只读。
  • 返回 MutableList<T>:调用方可以修改。

不要把内部可变集合直接暴露出去。

安全访问

Java 常见异常式访问:

list.get(0);

Kotlin 提供安全替代:

val first = list.firstOrNull()
val item = list.getOrNull(index)
val only = list.singleOrNull()

函数名里的 OrNull 是重要契约:调用方必须处理没有结果的情况。

转换与过滤

val activeNames = users
    .filter { it.active }
    .map { it.name }
    .sorted()

可空过滤:

val names: List<String?> = listOf("Ada", null, "Grace")
val nonNullNames: List<String> = names.filterNotNull()

类型过滤:

val strings = values.filterIsInstance<String>()

分组与关联

val usersByRole = users.groupBy { it.role }
val userById = users.associateBy { it.id }
val nameById = users.associate { it.id to it.name }

这些 API 通常比手写 HashMap 填充循环更清晰。

作用域函数

作用域函数不是魔法,只是让对象上下文更短:

val request = Request().apply {
    method = "GET"
    path = "/users"
}

response.also {
    logger.info("response={}", it)
}

nullableUser?.let {
    sendWelcomeEmail(it)
}

过度嵌套会降低可读性。代码复杂时,局部变量和普通 if 更好。

require/check/error

参数校验:

fun setAge(age: Int) {
    require(age >= 0) { "age must be non-negative" }
}

状态校验:

check(connection.isOpen) { "connection must be open" }

不应发生的分支:

else -> error("unknown state: $state")

这比手写 if (...) throw ... 更统一,也能帮助智能转换。

Result

Result<T> 可用于表达成功或失败:

fun parseInt(input: String): Result<Int> =
    runCatching { input.toInt() }

val value = parseInt("42")
    .getOrElse { 0 }

注意:不要把所有异常都机械包装成 Result。对于业务错误,sealed class 结果类型常常更清晰;对于违反契约的错误,异常仍然合理。

字符串工具

text.isBlank()
text.isNullOrBlank()
text.trim()
text.substringBefore("@")
text.substringAfter("@")
text.removePrefix("Bearer ")

字符串模板:

val message = "User ${user.id}: ${user.name}"

多行字符串:

val sql = """
    SELECT id, name
    FROM users
    WHERE active = true
""".trimIndent()

范围与进度

for (i in 1..10) {}
for (i in 1 until 10) {}
for (i in 10 downTo 1 step 2) {}

if (age in 0..120) {
    println("valid")
}

until 不包含右边界,适合索引:

for (i in 0 until list.size) {
    println(list[i])
}

但需要索引和值时优先:

for ((index, value) in list.withIndex()) {
    println("$index -> $value")
}

use 关闭资源

Java try-with-resources:

try (var reader = Files.newBufferedReader(path)) {
    return reader.readLine();
}

Kotlin:

File("input.txt").bufferedReader().use { reader ->
    println(reader.readLine())
}

use 会在代码块结束后关闭资源,即使发生异常。

TODO 与 NotImplementedError

fun calculate(): Int {
    TODO("not implemented yet")
}

TODO() 返回 Nothing,可以放在任意返回类型的位置。它适合开发占位,但不能留在生产路径中。

Java 迁移建议

  • map/filter/groupBy/associateBy 替代简单循环填充集合。
  • firstOrNull/getOrNull/toIntOrNull 替代可预期失败的异常。
  • 用字符串模板替代字符串拼接。
  • require/check 替代零散参数和状态校验。
  • use 替代 try-finally 资源关闭。
  • 不要为了“函数式”牺牲可读性,复杂流程仍可用普通循环。

实践建议

  • 标准库函数名通常带语义提示,例如 OrNullNotNullToBy,阅读时要关注这些后缀。
  • 小集合普通链式调用即可,大数据多步处理再考虑 Sequence
  • 公共 API 的集合返回类型尽量只读。
  • 对可预期缺失使用可空值,对违反契约使用异常。
  • 先写清楚,再写短;Kotlin 的简洁来自表达力,不是压缩行数。

参考

  • Kotlin 标准库 API:https://kotlinlang.org/api/core/