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 教程。