相传NPE值十亿美金。哇~那是好多
Kotlin为何这么?号称解决了NPE呢?
① NPE从哪里来
② Kotlin从哪几个方面解决了NPE
③ Kotlin到底解决了什么?
④ 在什么时候,Kotlin的NPE解决方案是失灵的?
有四个来源
val list = ArrayList() // 非空(构造函数结果)
list.add("Item")
val size = list.size // 非空(原生 int)
val item = list[0] // 推断为平台类型(普通 Java 对象)
item.substring(1) // 允许,如果 item == null 可能会抛出异常
fun main() {
var a: String = "abc"
a = null // 编译错误
}
若 a 声明为String! 则 可为空
fun main() {
var b: String? = "abc"
b = null // ok
print(b)
}
访问 val l = a.length
这就不会报错
访问val l = b.length // 错误:变量“b”可能为空
编译器会报错
就是用if …else进行判空
val l = if (b != null) b.length else -1
这里增加了 ?.操作符。
在java中是这样的
bob.department.head.name
只要有一个环节为null就报npe
在Kotlin中可以这样
bob?.department?.head?.name
任一环节为null,就会返回 null
可以与 let 一起使用
fun main() {
val listWithNulls: List = listOf("Kotlin", null)
for (item in listWithNulls) {
item?.let { println(it+" is the result") } // 输出 Kotlin 并忽略 null
}
}
输出
Kotlin is the result
// 如果 person
或者 person.department
其中之一为空,都不会调用该函数:
person?.department?.head = managersPool.getManager()
在这里范例中,只要左侧返回null,就跳过右侧表达式的求值
注意
不要在右侧表达式做过多的处理,尽量纯净,小心处理会依赖这部分逻辑的操作,避免埋坑
当我们有一个可空的引用 r 时,我们可以说“如果 r 非空,我使用它;否则使用某个非空的值 x”
一般是这样写的
val l: Int = if (r != null) r.length else -1
这个表达式,就可以改写为
val l = r?.length ?: -1
?: 左侧表达式非空,?: (elvis 操作符)就返回其左侧表达式,否则返回右侧表达式
throw 和 return 在 Kotlin 中都是表达式,
所以,右侧的表达式也支持throw和return
fun foo(node: Node): String? {
val parent = node.getParent() ?: return null
val name = node.getName() ?: throw IllegalArgumentException("name expected")
// ……
}
如果你想要一个 NPE,你必须显式要求它
就用到!!操作符
val l = b!!.length
b为null的话,就会强制抛出NPE
对象不是目标类型,常规类型转换可能会导致 ClassCastException。
进行安全类型转换
val aInt: Int? = a as? Int
你有一个可空类型元素的集合,但你想要过滤非空元素
val nullableList: List = listOf(1, 2, null, 4)
val intList: List = nullableList.filterNotNull()
这个问题从 NPE的来源中可以知道了
Kotlin的NPE方案,的确解决了很多麻烦地方。但目前来,其实,如果你不怕麻烦,你可以无限的编写各种if…else来处理。
一个非常富有耐心的程序员可以手动解决NPE。各种判断,各种判断,往死里写。
但这太累了。所以,至少我不会这么干。总是挑一些没把握的地方去写。
Kotlin提供了什么呢?
一种快捷处理NPE的方式。它并没有完全规避NPE。但它改变了NPE处理的方式
5招就改变了 程序员对NPE的关注程度,关注层级不一样,自然就不容易犯错了;减少了编码的工作量,写起来不累就不会产生抵触。
可以说,Kotlin的5招 cover了很多场景。
最容易出问题的当属 跨平台的互操作。比如java与kotlin。
java和kotlin是有互操作性。所以,需要留意类型转换是否有进行,这需要人为的去控制。
组件化、模块化、AOP思想,在合理的框架下,控制Kotlin接入的值,处理不当就容易出问题,这时就会失灵。