Kotlin语言基础笔记
Kotlin流程控制语句笔记
Kotlin操作符重载与中缀表示法笔记
Kotlin扩展函数和扩展属性笔记
Kotlin空指针安全(null-safety)笔记
Kotlin类型系统笔记
Kotlin面向对象编程笔记
Kotlin委托(Delegation)笔记
Kotlin泛型型笔记
Kotlin函数式编程笔记
Kotlin与Java互操作笔记
Kotlin协程笔记
多年的java开发经验总结得出,至少50%以上的线上bug都是NPE(NullPointException)引起的。在java代码中充斥着大量的非空判断,如果是有多层的对象,比如person.getAddress().getCity(),你需要判断person非空,然后判断address非空,只有两个都非空时,才能安全的获取到city。这样的代码非常冗余和恶心。
现在我们来看看Kotlin做了那些事情让我们来避免NPE错误。
1. 可为null类型
在Kotlin中通常我们直接定义的类型是不可为null的,如下:
data class Person(val name:String)
fun main(args: Array<String>) {
var s = "abc"
s = null //编译错误:null can not be a value of a non-null type String
var i = 1
i = null //编译错误:null can not be a value of a non-null type Int
var p = Person("Denny")
p = null //编译错误:null can not be a value of a non-null type Person
}
如果要允许为null,我们需要在变量的类型后面加个?
号。如下:
data class Person(val name:String)
fun main(args: Array<String>) {
var s: String? = "abc"
s = null
var i:Int? = 1
i = null
var p:Person? = Person("Denny")
p = null
var list:MutableList<Int>? = mutableListOf(1, 2, 3)
list = null
}
2. 安全调用
上面的例子中,如果调用s.length的话,这将是不安全的,编译器直接报错。
npe
编译器已经告诉你了要使用安全调用(
?.
)或者非空断言调用(!!.
)才被允许在String?类型上。
fun main(args: Array<String>) {
var s: String? = "abc"
s = null
println(s?.length) //打印null
println(s!!.length) //抛出Exception in thread "main" kotlin.KotlinNullPointerException异常
}
另外我们再看看下面这段有趣的代码:
fun main(args: Array<String>) {
var s: String? = "abc"
println(s is Any) //打印true
println(s is Any?) //打印true
s = null
println(s is Any) //打印false
println(s is Any?) //打印true
}
安全调用在链式调用上非常有用,比如上面java代码person.getAddress().getCity(),在Kotlin中使用安全调用的话就是person?.getAddress()?.getCity()
。只要person或者address有一个为null的话,整个表达式就返回null。比java中用2个if来判断非空好多了。
如果对某个非空值执行某个操作,安全调用操作符可以和let
一起使用。比如:
fun main(args: Array<String>) {
val list = listOf("a", "b", null)
println(list)
list.forEach { it?.let { println(it) } }
}
输出
[a, b, null]
a
b
最后你还可以使用Elvis错作符,之前的文章有说过。
fun main(args: Array<String>) {
var name:String? = null
name = name?:"Unknown"
println(name) //打印Unknown
}