Kotlin空指针安全(null-safety)笔记

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) {
    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) {
    var s: String? = "abc"
    s = null

    var i:Int? = 1
    i = null

    var p:Person? = Person("Denny")
    p = null

    var list:MutableList? = mutableListOf(1, 2, 3)
    list = null
}

2. 安全调用

上面的例子中,如果调用s.length的话,这将是不安全的,编译器直接报错。

Kotlin空指针安全(null-safety)笔记_第1张图片
npe

编译器已经告诉你了要使用安全调用( ?.)或者非空断言调用( !!.)才被允许在String?类型上。

fun main(args: Array) {
    var s: String? = "abc"
    s = null
    println(s?.length)  //打印null
    println(s!!.length)  //抛出Exception in thread "main" kotlin.KotlinNullPointerException异常
}

另外我们再看看下面这段有趣的代码:

fun main(args: Array) {
    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) {
    val list = listOf("a", "b", null)
    println(list) 

    list.forEach { it?.let { println(it) } }
}

输出

[a, b, null]
a
b

最后你还可以使用Elvis错作符,之前的文章有说过。

fun main(args: Array) {
    var name:String? = null
    name = name?:"Unknown"
    println(name)   //打印Unknown
}

你可能感兴趣的:(Kotlin空指针安全(null-safety)笔记)