1. 概述
在许多编程语言中,访问空引用(null reference)是最常见的 bug 之一,这通常会导致抛出 NullPointerException
。Kotlin 提供了多种机制来帮助我们避免 null 值带来的问题,其中之一就是 Elvis 运算符(?:)。本文将通过几个简洁的示例,带你了解 Elvis 运算符的用法和注意事项。
2. 什么是 Elvis 运算符
Elvis 运算符由一个问号加一个冒号组成:?:
。
这个名字来源于它的外观:从侧面看像是猫王 Elvis 的标志性发型。
Elvis 运算符也被称为 null 合并运算符(null coalescing operator) 或 空安全运算符(null-safety operator)。
其作用是:如果左侧表达式不为 null,则返回左侧值;否则返回右侧值。
使用 Elvis 运算符可以写出更简洁、可读性更高的 null 安全代码。
3. 基本语法
先来看一个没有使用 Elvis 运算符的写法:
var word: String? = "Elvis"
val length: Int = if (word != null) word.length else -1
assertEquals(5, length)
使用 Elvis 运算符可以简化为:
val word: String? = "Elvis"
val length: Int = word?.length ?: -1
assertEquals(5, length)
✅ 解释:
word?.length
是安全调用操作符,如果word
为 null 则返回 null。?:
则判断左侧是否为 null,是则返回右侧值-1
。
再来看一个 null 的情况:
val word: String? = null
val length: Int = word?.length ?: -1
assertEquals(-1, length)
❌ 注意:Elvis 运算符只能用于处理可能为 null 的值(即类型为 T?
的变量)。
3.1 结合 throw 和 return 使用
Elvis 右侧不仅可以是普通值,也可以是 throw
或 return
表达式:
val word: String? = null
val exception = assertThrows(IllegalArgumentException::class.java) {
word?.length ?: throw IllegalArgumentException("empty string not allowed")
}
assertEquals("empty string not allowed", exception.message)
✅ 优点:可以用于参数校验或提前终止逻辑。
3.2 多个 Elvis 运算符合并使用
可以链式使用 Elvis 运算符,依次尝试多个候选值:
val a = null
val b = null
val result = a ?: b ?: "a and b are null"
assertEquals("a and b are null", result)
这种写法非常适合用于配置回退或默认值设置。
4. 使用建议与踩坑提醒
- ✅ 推荐在处理可空类型时优先使用 Elvis,代码更简洁清晰。
- ❌ 不要滥用 Elvis,尤其是在你不确定左侧表达式是否真的可能为 null。
- ⚠️ Elvis 运算符右侧的表达式在左侧为 null 时才会执行,因此如果右侧有副作用(如函数调用),要特别注意执行时机。
- ✅ 可用于返回值、异常抛出、链式默认值等场景,非常灵活。
5. 总结
Elvis 运算符是 Kotlin 中非常实用的一个操作符,它以一种简洁且安全的方式处理 null 值。通过本文的示例你应该已经掌握了它的基本用法和一些进阶技巧。熟练使用 Elvis 可以有效减少 null 相关的 bug,提升代码可读性和健壮性。
完整示例代码请参考:GitHub 示例地址