问题背景:
Elvis运算符(?:)是Kotlin中处理可空值的简单且安全的方式。由于从侧面看这个运算符与猫王埃尔维斯·普雷斯利的发型相似,因此得名。其目的是消除模板代码,例如if (a != null) a else b,并使日常开发更方便。
问题:
直接访问可能为null的值会导致运行时错误(NullPointerException)。因此,需要一种工具,可以优雅地替代为默认值,当变量为null时。
解决方案:
Elvis运算符适用于可空类型。如果运算符左侧的表达式不为null,则返回它;否则,返回右侧的表达式。这使得代码更加简洁和安全。
代码示例:
fun getLength(str: String?): Int { return str?.length ?: 0 } val result = getLength(null) // result == 0 val result2 = getLength("Hello") // result2 == 5
主要特点:
如果在Elvis运算符右侧的表达式有副作用,会发生什么?它是否总是执行?
不会!右侧的表达式仅在左侧为null时计算。如果函数有副作用或"昂贵"计算,这可能会很重要。
代码示例:
var called = false val x: String? = "test" val y = x ?: run { called = true; "default" } // called会等于false,因为run根本不会执行
可以使用Elvis运算符抛出异常吗?
可以,在Kotlin中可以这样写:
fun getLengthStrict(str: String?): Int = str?.length ?: throw IllegalArgumentException("str is null")
如果str为null,将会抛出异常。这个机制很有效地对数据进行验证。
可以"链接"多个Elvis运算符吗?
可以,这是一种常见的回退方法:
val name = fromDatabase ?: fromCache ?: "Unknown"
这个表达式将返回第一个非null值或字符串"Unknown"。
通过Elvis进行多级嵌套null检查:
val title = a?.b?.c?.d?.e ?: defaultTitle
优点:
缺点:
逐步明确拆解,明确变量名称:
val deepValue = a?.b val deeperValue = deepValue?.c?.d ?: default
优点:
缺点: