跳到主要内容

Kotlin 2.5 标准库新成员:onTrue、onFalse、ifOrNull 实战指南

· 阅读需 5 分钟
重庆 Kotlin User Group

在日常 Kotlin 开发中,你一定写过这样的代码:调用一个返回 Boolean 的方法,然后根据结果做点副作用——记个日志、发个通知、返回个值。这类模式看似简单,写多了却会让代码变得冗长而重复。Kotlin 2.5.0-Beta1 带来了三个小巧但实用的标准库函数,专门解决这类问题。

三个新函数一览​

函数接收者行为返回值
onTrue { }Boolean值为 true 时执行 lambda原始 Boolean 值
onFalse { }Boolean值为 false 时执行 lambda原始 Boolean 值
ifOrNull { }Boolean值为 true 时执行 lambda 并返回其结果lambda 结果或 null

这三个函数目前都是实验性的,需要 opt-in:

@OptIn(ExperimentalStdlibApi::class)

或在 build.gradle.kts 中全局配置:

kotlin {
compilerOptions {
freeCompilerArgs.add("-opt-in=kotlin.ExperimentalStdlibApi")
}
}

onTrue():成功时执行副作用​

最常见的场景:对集合执行 add() 或 remove() 后,根据返回值做日志记录或通知。

改造前​

val tags = mutableSetOf("kotlin", "jvm")

val added = tags.add("wasm")
if (added) {
println("Tag 'wasm' added successfully")
}

改造后​

@OptIn(ExperimentalStdlibApi::class)
fun main() {
val tags = mutableSetOf("kotlin", "jvm")

val added = tags.add("wasm")
.onTrue { println("Tag 'wasm' added successfully") }

println(added) // true
}

onTrue 的关键设计:lambda 执行完后,返回的是原始 Boolean 值,而不是 lambda 的返回值。这意味着你可以在链式调用中无缝插入副作用,不影响后续逻辑。

onFalse():失败时执行副作用​

与 onTrue 对称,onFalse 在值为 false 时触发。

@OptIn(ExperimentalStdlibApi::class)
fun main() {
val tags = mutableSetOf("kotlin", "jvm")

val removed = tags.remove("native")
.onFalse { println("Tag 'native' not found, nothing to remove") }

println(removed) // false
}

链式组合​

onTrue 和 onFalse 可以链式组合,替代完整的 if-else:

@OptIn(ExperimentalStdlibApi::class)
fun processOrder(orderId: String): Boolean {
return orderRepository.save(orderId)
.onTrue { logger.info("Order $orderId saved") }
.onFalse { logger.warn("Failed to save order $orderId") }
}

对比原来的写法:

fun processOrder(orderId: String): Boolean {
val saved = orderRepository.save(orderId)
if (saved) {
logger.info("Order $orderId saved")
} else {
logger.warn("Failed to save order $orderId")
}
return saved
}

链式写法不仅更简洁,而且保持了数据的流动感——返回值直接沿着调用链传递,不需要额外的临时变量。

ifOrNull():条件性生成值​

ifOrNull 解决的是另一类常见问题:根据条件决定返回一个值还是 null。

改造前​

fun getWasmMessage(tags: Set<String>): String? {
return if ("wasm" in tags) {
"Wasm tag is available"
} else {
null
}
}

改造后​

@OptIn(ExperimentalStdlibApi::class)
fun getWasmMessage(tags: Set<String>): String? {
return ifOrNull("wasm" in tags) {
"Wasm tag is available"
}
}

实战:条件性构建对象​

@OptIn(ExperimentalStdlibApi::class)
data class SearchResult(
val query: String,
val results: List<String>,
val cachedAt: Long? = null,
)

fun searchFromCache(query: String, cache: Map<String, List<String>>): SearchResult? {
// 缓存命中时构建结果,未命中时返回 null
return ifOrNull(cache.containsKey(query)) {
SearchResult(
query = query,
results = cache[query]!!,
cachedAt = System.currentTimeMillis(),
)
}
}

这比写一个完整的 if-else 返回 null 要优雅得多,尤其在函数体较长时,ifOrNull 能显著减少缩进层级。

完整示例:组合使用三个函数​

来看一个综合场景——用户注册流程:

@OptIn(ExperimentalStdlibApi::class)
class UserRegistry {
private val users = mutableSetOf<String>()
private val blacklist = setOf("admin", "root", "system")

fun register(username: String): String? {
return username.isNotBlank()
.onFalse { println("Rejected: blank username") }
.let { it && username !in blacklist }
.onFalse { println("Rejected: '$username' is blacklisted") }
.let { valid ->
ifOrNull(valid) {
users.add(username)
.onTrue { println("User '$username' registered") }
.onFalse { println("User '$username' already exists") }
username
}
}
}
}

fun main() {
val registry = UserRegistry()

println(registry.register("alice")) // User 'alice' registered → alice
println(registry.register("alice")) // User 'alice' already exists → null
println(registry.register("")) // Rejected: blank username → null
println(registry.register("admin")) // Rejected: 'admin' is blacklisted → null
}

底层实现原理​

这三个函数的实现非常简洁,直接看源码就能理解:

@ExperimentalStdlibApi
public inline fun Boolean.onTrue(action: () -> Unit): Boolean {
if (this) action()
return this
}

@ExperimentalStdlibApi
public inline fun Boolean.onFalse(action: () -> Unit): Boolean {
if (!this) action()
return this
}

@ExperimentalStdlibApi
public inline fun <T> ifOrNull(condition: Boolean, action: () -> T): T? {
return if (condition) action() else null
}

注意几个设计细节:

  1. inline 修饰:三个函数都是内联函数,不会有额外的函数调用开销
  2. onTrue/onFalse 返回 Boolean:而非 lambda 的返回值(Unit),保证链式调用的流畅性
  3. ifOrNull 是顶层函数:接收者不是 Boolean,而是作为普通参数传入,这是因为它需要返回泛型类型 T?,而 Boolean 作为接收者时泛型推断会有歧义

何时使用,何时避免​

适合使用的场景​

  • 集合操作后的日志记录(add()、remove() 返回 Boolean)
  • 条件性返回值(替代 if (cond) value else null)
  • 链式调用中插入副作用

不适合使用的场景​

  • 条件分支逻辑复杂时——when 表达式更清晰
  • 需要多个不同条件的组合判断——传统 if-else 更直观
  • 团队不熟悉这些新 API 时——可读性优先于简洁性

总结​

onTrue()、onFalse()、ifOrNull() 是 Kotlin 标准库「让常见模式更简洁」这一设计哲学的又一次体现。它们并不改变语言的能力边界,但能让日常代码更加流畅:

  • onTrue / onFalse:为 Boolean 结果链式添加副作用,替代 if (x) { ... } 的样板代码
  • ifOrNull:条件性生成值,替代 if (cond) value else null 的冗余分支

这三个函数目前处于实验阶段,API 签名可能在后续版本中调整。如果你在项目中想尝试,建议先通过全局 opt-in 在小范围内验证,等正式稳定后再大规模采用。