一、? 与 !! 的比较
val a: String = "aa" /* * a是非空类型,下面的给a赋值为null将会编译不通过 * */ // a = null a.length /* * ?声明是可空类型,可以赋值为null * */ var b: String? = "bb" b = null /* * b是可空类型,直接访问可空类型将编译不通过,需要通过?.或者!!.来访问 * */ // b.length b?.length b!!.length
- 对于一个不可为空类型:如果直接给不可为空类型赋值一个可能为空的对象就在编译阶段就不能通过
- 对于一个可空类型:通过?声明,在访问该类型的时候直接访问不能编译通过,需要通过?.或者!!.
- ?. 代表着如果该类型为空的话就返回null不做后续的操作,如果不为空的话才会去访问对应的方法或者属性
- !!. 代表着如果该类型为空的话就抛出NullPointerException,如果不为空就去访问对应的方法或者属性, 所以只有在很少的特定场景才用这种符号,代表着程序不处理这种异常的case了,会像java代码一样抛出NullPointerException。 而且代码中一定不用出现下面这种代码,会让代码可读性很差而且如果有空指针异常,我们也不能马上发现是哪空了:
/*
* 不推荐这样的写法:链式的连续用!!.
* */
val user = User()
user!!.name!!.subSequence(0,5)!!.length
二、let语句简化对可空对象对访问
- let函数默认当前这个对象作为闭包的it参数,返回值是函数里面最后一行,或者指定return。
* 通过let语句,在?.let之后,如果为空不会有任何操作,只有在非空的时候才会执行let之后的操作 * */ user?.let { it.name it.age it.toString() }
三、?: 简化对空值的处理
?:符号会在符号左边为空的情况才会进行下面的处理,不为空则不会有任何操作。跟?.let正好相反,例如我们可以用两行代码来简化上面从操作:
/**
* Elvis操作符 ?: 简化对空值的处理
*/
fun testElvis2(input: String?, user: User?) {
val b = input?.length ?: -1;
user?.save() ?: User().save()
}