
所有的变量除了引用一个具体的值之外,还有一种特殊的值可以使用,那就是null,它代表空值,也就是不引用任何对象。
在 Java 中null是一个非常常见的值,因为在某些情况下,引用类型的变量默认值就是 null,这就经常会导致程序中出现一些空指针导致的异常;在 Kotlin 中,对空值处理是非常严格的,正常情况下,变量是不能直接赋值为null的,否则会报错,无法编译通过:
var str: String = null // 编译错误
所有的类型默认为非空类型,非空类型的变量是不允许被赋值为 null 的,这直接在编译阶段就避免了其他语言中经常存在的空指针问题。
如果希望某个变量在初始情况下使用null而不去引用某一个具体对象,此时需要将变量的类型修改为可空类型,只需在类型名称的后面添加一个?
var str: String? = null
既然现在是可空类型,那么很多问题就会出现,比如当一个变量为null时,此时如果使用类中的一些成员方法或是获取成员属性时,会出现一些问题:
var str: String? = null
println(str.length); // 编译错误
这里由于操作的是一个空类型,它有可能值为null,可以想象一下,如果一个变量不引用任何对象,此时又让对象做一些事情(执行函数),而压根就没这个对象,这会导致上面所说的空指针异常。
此时,为了安全,需要对变量进行判断,看看其是否不为null然后才能去做一些正常情况下该做的事情:
fun main() {
var str: String? = null
// 这里直接通过if语句判断str变量是否为null,如果不是才执行
if (str != null) {
println(str.length) // 现在就可以编译通过了
}
}
只要能确保某个空类型变量的值不为空,那么就可以正常执行操作。实际上在 if 内部,因为已经判断不为 null 了,所以 str 被智能类型转换为非空类型。
在有些情况下,我们可能已经非常清楚,这里的 str 一定不为 null,即使它是一个可空类型变量。我们可以告诉编译器,这里一定是安全的,只管执行就好:
fun main() {
var str: String? = null
// 使用非空断言操作符!!.来明确不会出现null问题
println(str!!.length)
}
虽然使用**非空断言操作符 !!**能够进行强制操作,实际上同样存在安全问题。也许存在没有考虑到的情况会导致这里为 null ,也说不定?对于一些我们拿不定具体会不会出现 null 的情况,有没有更好的解决办法?
Kotlin 提供了一种更安全的空类型操作,要安全地访问可能包含null值的对象的属性,请使用安全调用运算符?.,如果对象的属性为null则安全调用运算符返回null,像下面这样:
fun main() {
var str: String? = null
println(str?.length) // 使用安全调用运算符 ?.
}
这里的调用结果存在两种情况:
- 如果 str 为 null,那么这里得到的结果就是 null,并且不会正常执行后面的操作
- 如果 str 不为 null,那就正常返回这里本应该得到的结果
因此,使用安全调用运算符后,如果遇到 null 的情况,那么不会正常进行原本的操作,而是直接返回null作为结果,这在有些时候非常好用,比如希望一个学生类型的变量在为null时就不执行对应的语句:
fun main() {
val stu: Student? = null
stu?.hello()
}
不过在有些时候,可能希望如果变量为 null,在使用安全调用运算符时,返回一个自定义的结果,而不是null,这时该怎么做呢?我们可以使用 Elvis 运算符 ?:
fun main() {
val str: String? = null
// Elvis运算符 ?: 左侧为空值检测目标,右侧为检测到null时返回的结果
val len: Int = str?.length ?: 0
}W
这里使用了 Elvis 运算符来判断左侧是否为 null,如果左侧为 null,那么这里直接得到右侧的自定义值,这个运算符长得像其他语言里面的三元运算符。
Kotlin空值与空类型详解
703

被折叠的 条评论
为什么被折叠?



