Kotlin 空值安全
Kotlin 在设计时特别关注了空指针异常(NullPointerException
,简称 NPE)的问题,这是许多编程语言中常见的错误类型之一。通过其独特的空值处理逻辑和编译时严格的空值检查,可以有效减少空指针异常的产生
可空类型和非空类型
在 Kotlin 中,所有类型默认都是非空类型,即不允许值为 null
(例如,String
类型变量的值不能为 null
),否则会导致编译报错,如果想允许值为 null
,需要在类型声明后加上 ?
符号,将其显式声明为可空类型
对于可空类型,Kotlin 还会强制进行空值检查,如果一个可空类型的变量在使用前没有进行空值检查,也会导致编译报错
kotlin
// 当值可能为 null 时, 应在类型声明后使用 ? 显式声明其为可空类型
fun parseInt(str: String?): Int? {
if (str == null) return null
return str.toIntOrNull()
}
// 可空类型在使用前需要进行空值检查, 否则会导致编译报错
fun main() {
val x = parseInt(null)
val y = parseInt("1")
if (x != null && y != null) {
println(x * y)
} else {
println("Either '$x' or '$y' is not a number")
}
}
类型自动转换
当一个可空类型的变量通过空值检查后,Kotlin 会自动将该变量视为非空类型,只要该变量不重新赋值,后续的使用中就无需再次进行空值检查
kotlin
fun printLengthA(text: String?) {
// 下方两处 text.length 中, text 均通过了空值检查并被视为非空类型 String
if (text == null || text.length == 0) {
println("Test is empty")
return
}
println(text.length)
}
fun printLengthB(text: String?) {
// 在该条件分支内, text 被视为非空类型 String
if (text != null) {
println(text.length)
}
// 脱离了空值检测环境, 此处依旧被视为可空类型 String?
println("Not sure if text is null")
}
空值运算符
Kotlin 提供了一系列空值运算符,用于简化与空值有关的操作:
?.
安全调用运算符,当对象不为null
时,执行后续的调用,否则返回null
?:
Elvis 运算符,当对象不为null
时,返回对象本身,否则返回提供的默认值!!
非空断言运算符,取消空值检查的约束,但可能会导致空指针异常(谨慎使用)
kotlin
// 使用 ?. 安全调用运算符, 遇到空值后不再继续调用, 直接返回 null
println(str?.length)
kotlin
// 使用 ?: Elvis 运算符, 遇到空值后返回提供的默认值
println(str?.length ?: -1)
// 可使用作用域函数 run 处理复杂默认值, 其中的最后一个表达式为 run 的返回值
println(str?.length ?: run {
println("Str is null")
-1
})
// 也可在遇到空值后直接抛出异常
println(str?.length ?: throw IllegalArgumentException("Str is null"))
kotlin
// 使用 !! 非空断言运算符, 取消空值检查约束, 但可能会导致空指针异常
println(str!!.length)