Kotlin 2.5 标准库新成员:onTrue、onFalse、ifOrNull 实战指南
在日常 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
}
注意几个设计细节:
inline修饰:三个函数都是内联函数,不会有额外的函数调用开销onTrue/onFalse返回Boolean:而非 lambda 的返回值(Unit),保证链式调用的流畅性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 在小范围内验证,等正式稳定后再大规模采用。