Kotlin 空值关键字
最后修改于 2025 年 4 月 19 日
Kotlin 的空安全系统有助于消除空引用异常。null 关键字表示值的缺失。本教程通过实际例子探讨了 Kotlin 中的空值处理。
基本定义
在 Kotlin 中,类型默认情况下是不可空的。要允许空值,您必须使用 ? 显式声明类型为可空。null 关键字表示一个空引用。Kotlin 提供了几个运算符来安全地处理空值。
可空类型声明
要声明一个可以包含 null 的变量,请在其类型后附加 ?。这使得该类型可空。如果没有 ?,该变量就不能包含 null。
package com.zetcode
fun main() {
var name: String = "Kotlin"
// name = null // Compilation error
var nullableName: String? = "Kotlin"
nullableName = null // Valid
println(nullableName) // Output: null
}
这里,name 不能为 null,而 nullableName 可以。注释行将导致编译错误。这展示了 Kotlin 在编译时的空安全性。
安全调用运算符 (?.)
安全调用运算符 ?. 允许您安全地访问可空对象的属性或方法。如果对象为 null,则表达式返回 null 而不是抛出异常。
package com.zetcode
fun main() {
val str: String? = null
val length = str?.length
println(length) // Output: null
val str2: String? = "Hello"
println(str2?.length) // Output: 5
}
第一个安全调用返回 null,因为 str 为 null。第二个调用返回长度,因为 str2 包含一个字符串。这可以防止 NullPointerException。
Elvis 运算符 (?:)
Elvis 运算符 ?: 在可空表达式为 null 时提供默认值。它类似于其他语言中的三元运算符,但专门用于空值检查。
package com.zetcode
fun main() {
val name: String? = null
val length = name?.length ?: 0
println(length) // Output: 0
val name2: String? = "Kotlin"
println(name2?.length ?: 0) // Output: 6
}
当 name 为 null 时,Elvis 运算符返回 0。当 name2 有一个值时,它返回字符串长度。这为 null 值提供了一个安全的后备方案。
非空断言 (!!)
非空断言运算符 !! 将任何值转换为非空类型。如果该值为 null,则抛出 NullPointerException。仅当您确定该值不为 null 时才使用此运算符。
package com.zetcode
fun main() {
val str: String? = "Kotlin"
println(str!!.length) // Output: 6
val str2: String? = null
// println(str2!!.length) // Throws NullPointerException
}
第一个断言成功,因为 str 不为 null。注释行将抛出异常,因为 str2 为 null。此运算符应谨慎使用。
使用 as? 的安全转换
安全转换运算符 as? 尝试转换,如果失败则返回 null。这结合了空安全性和类型转换,防止了 ClassCastException。
package com.zetcode
fun main() {
val obj: Any = "Kotlin"
val str: String? = obj as? String
val num: Int? = obj as? Int
println(str) // Output: Kotlin
println(num) // Output: null
}
第一个转换成功,因为 obj 是一个 String。第二个转换失败,但返回 null 而不是抛出异常。这比常规转换更安全。
带有可空的 let 函数
let 函数仅当对象不为 null 时才执行一个块。它对于安全地对可空对象执行操作非常有用。
package com.zetcode
fun main() {
val name: String? = "Kotlin"
name?.let {
println("Name length is ${it.length}") // Output: Name length is 6
}
val nullName: String? = null
nullName?.let {
println("This won't be printed")
}
}
第一个 let 块执行,因为 name 不为 null。第二个块不执行,因为 nullName 为 null。这种模式在 Kotlin 中常用于空安全操作。
延迟初始化属性
lateinit 修饰符允许稍后初始化非空属性。当依赖注入或测试设置提供值时,这很有用。
package com.zetcode
class User {
lateinit var name: String
fun initialize() {
name = "Kotlin"
}
fun printName() {
if (::name.isInitialized) {
println(name)
}
}
}
fun main() {
val user = User()
// println(user.name) // Throws UninitializedPropertyAccessException
user.initialize()
user.printName() // Output: Kotlin
}
name 属性声明时没有 null,但稍后初始化。在初始化之前访问它会抛出异常。isInitialized 检查验证初始化状态。
空安全性的最佳实践
- 首选非空类型:尽可能使用非空类型进行设计以避免空值检查。
- 使用安全调用:更喜欢
?.而不是!!以获得更安全的代码。 - 提供默认值:使用 Elvis 运算符为 null 值提供合理的默认值。
- 考虑 lateinit:对于稍后初始化的属性,使用
lateinit而不是可空类型。 - 利用 let:使用
let进行空安全作用域函数。
来源
本教程深入介绍了 Kotlin 的 null 关键字和空安全特性。我们探讨了可空类型、安全调用、Elvis 运算符等等。适当的空值处理使 Kotlin 代码更健壮,更不易出现运行时异常。
作者
列出 所有 Kotlin 教程。