3.3 安全操作符

扔掉Java中的一堆null的防御式样板代码吧!当我们使用Java开发的时候,我们的代码大多是防御性的。如果我们不想遇到NullPointerException,就需要在使用它之前不停地判断它是否为null。

Kotlin正如很多现代编程语言一样是空安全的。因为我们需要通过一个可空类型符号“T?”来明确地指定一个对象类型T是否能为空。

我们可以像这样去写:

    >>> val str: String = null  //编译不通过: 不可空String类型的str禁止赋值null
    error: null can not be a value of a non-null type String
    val str: String = null
                      ^

可以看到,这里不能通过编译,因为String类型不能是null。

一个可以赋值为null的String类型的正确写法是:String?,代码如下:

    >>> var nullableStr: String? = null
             //可空类型 String?,nullableStr可能会导致空指针异常
    >>> nullableStrnull

我们再来看一下Kotlin中关于null的一些有趣的运算。null与null是相等的:

    >>> null==null
    true
    >>> null!=null
    false

null这个值比较特殊,null不是Any类型,例如:

    >>> null is Any
    false

但是,null是Any?类型,例如:

    >>> null is Any?
    true

我们再来看看null对应的类型是什么:

    >>> var a=null
    >>> a
    null
    >>> a=1
    error: the integer literal does not conform to the expected type Nothing?
    a=1
      ^

从报错信息中可以看出,null的类型是Nothing?。关于Nothing?的内容,将会在后面介绍。

3.3.1 安全调用符“?”

我们不能直接使用可空的nullableStr来调用其属性或者方法,例如下面的代码直接报错:

    >>> nullableStr.length
    error: only safe (?.) or non-null asserted (!!.) calls are allowed on a
    nullable receiver of type String?
    nullableStr.length
               ^

上面的代码无法编译,nullableStr可能是null。我们需要使用安全调用符“?.”来调用:

    >>> var nullableStr: String? = null
    >>> nullableStr?.length
    null
    >>> null ableStr = "abc"
    >>> nullableStr?.length //安全调用符“?.”
    3

只有在nullableStr!=null时才会去调用其length属性。

3.3.2 非空断言“!!”

Kotlin中提供了断言操作符“!!”,使得可空类型对象可以调用成员方法或者属性(但遇见null,就会导致空指针异常),代码示例如下:

    >>> nullableStr = null
    >>> nullableStr!!.length           //抛出空指针异常
    kotlin.KotlinNullPointerException

3.3.3 Elvis运算符“?:”

使用Elvis操作符“?:”来给定一个在null情况下的替代值:

    >>> nullableStr
    null
    >>> var s= nullableStr?:"NULL" //当s是null的时候,返回"NULL"字符串
    >>> s
    NULL