1. 概述

在许多编程语言中,访问空引用(null reference)是最常见的 bug 之一,这通常会导致抛出 NullPointerExceptionKotlin 提供了多种机制来帮助我们避免 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 右侧不仅可以是普通值,也可以是 throwreturn 表达式:

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 示例地址


原始标题:Kotlin Elvis Operator