在很多编程语言中 NullPointerException (NPE) 是最常见的异常之一,在 Java 中 NPE 就是空引用,引用空对象时出现的空指针异常,该异常在源程序中可以不进行捕获和处理。在Kotlin语言中解决了这个空异常问题,下面来看看它是怎样做到空安全的。
空指针异常Kotlin 官方文档给出了 NPE 可能出现的原因:
-
显式调用
throw NullPointerException()
; -
使用了下文描述的
!!
操作符; -
有些数据在初始化时不一致,例如当:
- 传递一个在构造函数中出现的未初始化的
this
并用于其他地方(“泄漏this
”); - 超类的构造函数调用一个开放成员,该成员在派生中类的实现使用了未初始化的状态;
- 传递一个在构造函数中出现的未初始化的
-
Java 互操作:
- 企图访问平台类型的
null
引用的成员; - 用于具有错误可空性的 Java 互操作的泛型类型,例如一段 Java 代码可能会向 Kotlin 的
MutableList<String>
中加入null
,这意味着应该使用MutableList<String?>
来处理它; - 由外部 Java 代码引发的其他问题。
- 企图访问平台类型的
1. 空的类型
Kotlin 空类型分为:可空类型 和 非空类型;
-
非空类型
常规变量不能容纳 null;
fun main() {
var a: String = "abc"
a = null // 编译错误
}
-
可空类型
使用?
操作符声明可空类型,避免抛出 NPE;
fun main() {
var b: String? = "abc"
b = null // ok
println(b) // 输出 null
}
2. 空的安全调用
1)使用?.
操作符安全调用,避免抛出 NPE;
fun main() {
var a = "abc"
var b :String? = null
println(a?.length) // 无需安全调用
println(b?.length) // 输出 null
}
如果 b 非空,就返回 b.length,否则返回 null,这个表达式的类型是 Int?。
2)使用操作符?.
与let
一起使用,只对非空值执行操作;
fun main() {
val listWithNulls: List<String?> = listOf("abc", null)
for (item in listWithNulls) {
item?.let { println(it) } // 输出 abc 并忽略 null
}
}
3)使用 Elvis (?:
) 操作符,检查结果为空的时候的返回值;
fun main() {
var b :String? = null
val l = b?.length ?: -1
println(l) // 输出 -1
}
如果?:
左侧表达式非空,elvis 操作符就返回其左侧表达式,否则返回右侧表达式。 请注意,当且仅当左侧为空时,才会对右侧表达式求值。
4)使用!!
非空断言运算符,将任何值转换为非空类型,若该值为空则抛出 NPE;
fun main() {
var a = "abc"
var b :String? = null
println(a!!.length) // 输出3
println(b!!.length) //抛出 NPE异常
}
如果 b 非空,就返回 b.length,否则抛出 NPE异常。
5)使用as?
操作符尝试转换成指定类型,如果尝试转换不成功则返回 null;
fun main() {
var a = "abc"
var b: Int ? = a as? Int
println(b) // 输出 null
}
6)使用filterNotNull
操作符,过滤一个可空类型元素集合中的非空元素;
fun main() {
val nullableList: List<Int?> = listOf(1, 2, null, 4)
val intList: List<Int> = nullableList.filterNotNull()
println(intList) // 输出 [1, 2, 4]
}
3. 空的安全总结
空安全设计的操作符及描述,如下表:
操作符 | 描述 |
---|---|
? |
可空操作符,声明可空类型,避免抛出NPE; |
?. |
安全调用操作符,为空返回null,避免抛出NPE; |
?.let{} |
?. 与let 一起使用,用于遍历集合时,则忽略null值,只对非空值执行操作; |
?: |
Elvis操作符, val t = b?.length ?: -1 ,如果 ?: 左侧表达式(b?.length )非空,elvis 操作符就返回其左侧表达式,否则返回右侧表达式(-1 ); |
!! |
非空断言运算符,将任何值转换为非空类型,若该值为空则抛出NPE; |
as? |
尝试转换成指定类型,如果尝试转换不成功则返回null; |
filterNotNull |
过滤一个可空类型元素集合中的非空元素。 |
网友评论