安全调用操作符 '?.' 是 Kotlin 中应对 null 值的关键工具之一,作为一种提高安全性和便利性以处理可能缺失值的语言理念的发展而出现。
问题的背景: 在 Java 中,null 值常常是错误(NullPointerException)的来源。Kotlin 引入了严格的类型系统,明确区分可空和非可空变量,并伴随引入了一些便利工具以方便它们的使用。
问题: 如何在处理可能为 null 的对象时避免 NullPointerException,同时不牺牲代码的可读性和简洁性?
解决方案: 操作符 '?.' 允许顺畅地访问可空变量的属性和方法:如果对象不为 null,则执行调用;如果为 null,则返回 null(或根据需要进行后续逻辑)。
代码示例:
val user: User? = getUser() val name = user?.name // 如果 user != null,将返回 user.name,否则返回 null user?.printInfo() // 如果 user != null,将调用 printInfo()
关键特点:
安全调用操作符 '?.' 可以在赋值的左侧使用吗?
不可以。操作符 '?.' 不能用于安全赋值属性或变量;它仅用于访问或调用。以下是不正确的:
user?.name = "Alex" // 编译错误
可以通过显式检查安全地赋值属性:
user?.let { it.name = "Alex" }
当安全调用链第一次遇到 null 时会返回什么?
一旦链中的一个元素 '?.' 等于 null,表达式的结果将变为 null,后续的安全调用不会被执行。
示例:
user?.address?.zipCode // 如果 user 或 address == null,结果为 null
可以将安全调用 '?.' 与返回 Unit 的函数一起使用吗?
可以,调用仍将发生,只要对象不为 null;如果对象为 null,则返回 null 而不是 Unit。
示例:
user?.clearData() // 如果 user == null,什么也不会发生
开发者在长链安全调用后使用 '!!' 可能导致对象为 null:
val country = user?.address?.city?.country!!
优点:
缺点:
安全调用与 Elvis 操作符结合使用,以返回默认值:
val country = user?.address?.city?.country ?: "Unknown"
优点:
缺点: