前言
空指针异常(NPE)是最为普遍与常见的异常,同时它也会引起诸如程序崩溃等非常严重的后果。为了避免出现NPE,常常需要开发者对变量进行判空处理。特别是在Android中常常会使用‘链式’调用,但为了避免NPE,需要‘步步’判空,使得程序代码啰嗦且难以维护。为解决此问题,Kotlin提供了新的声明,用于保证空安全。
空安全
空安全简单来说可在两个阶段进行:
- 声明时保证空安全
- 使用时保证空安全
任何一个环节保证了空安全,则可避免空指针异常。
声明时保证空安全
-
Java
在Java中并不支持在声明变量时就保证空安全,即不支持在编译时就判断变量是否可能为空。 -
Kotlin
Kotlin提供了新的方式,用于声明变量是否可能为空。声明的语法为:
变量名:变量类型?
添加?的变量类型表示其对象可能为空。若不添加表示其对象不可能为空,在编译时就可以提前发现该问题。
var a: String = "abc"
a = null // 编译错误
var b: String? = "abc"
b = null // ok
在这一例子中,变量a没有声明为可空类型,若对其赋值为空,则会编译报错。但对于变量b声明为可空类型后,可以令其为空。
使用时保证空安全
- Java
在java中无法再声明时就保证空安全,为此要避免NPE,必须在使用变量时保证空安全。最基本也是最常见的手段就是:
if (b != null){
//xxx
}
- Kotlin
在Kotlin中如果某个变量声明为可空的类型,则在使用时也需要注意是否为空。Kotlin同样支持像Java那样显式判空。同时也提供了安全调用符,即 ?.
val a = "Kotlin"
val b: String? = null
println(b?.length)
println(a?.length)
如果b不为空,就返回b.length,若b为空,就返回null。该表达式的返回值类型为Int?
更为常见地,该调用符也可以支持’链式‘调用:
bob?.department?.head?.name
若其中任何一个环节为空,则返回空。
安全调用也可以出现在赋值的左侧。这样,如果调用链中的任何一个接收者为空都会跳过赋值,而右侧的表达式根本不会求值:
person?.department?.head = managersPool.getManager()
空处理
- Java
当我们有一个可空的引用 b 时,我们可以说“如果 b 非空,我使用它;否则使用某个非空的值 x”:
if (b != null){
return b.length;
} else {
return -1;
}
- Kotlin
要实现在变量为空时的处理,Kotlin不仅支持像Java那样的显式赋值,还拥有更为简单的操作符,即Elvis 操作符 ?:
val l = b?.length ?: -1
如果 ?: 左侧表达式非空,elvis 操作符就返回其左侧表达式,否则返回右侧表达式。 请注意,当且仅当左侧为空时,才会对右侧表达式求值。
额外操作符
- Kotlin
在Kotlin中还支持一些Java不支持的新的操作符,如!!操作符。
val l = b!!.length
如果该调用不为空,则返回预期值,若为空,则抛出空指针异常。
安全类型转换:如果对象不是目标类型,那么常规类型转换可能会导致 ClassCastException。 另一个选择是使用安全的类型转换,如果尝试转换不成功则返回 null:
val aInt: Int? = a as? Int
网友评论