您的位置:首页 > 其它

Kotlin学习笔记5-8 其他-空安全

2018-02-10 17:07 399 查看

空安全

Kotlin官网:Other-Null Safety

可空类型和不可空类型

Kotlin中将类型分为可空和不可空,以尽量避免空指针(NPE-NullPointerException)的问题。只有在如下情况下才会发生空指针异常:

主动抛出
throw NullPointerException()


!!
运算符;

被认为已经初始化,实际没有:

构造函数中将还未初始化完的this赋值给其他地方使用;

父类中使用了子类实现的成员,没有正确初始化;

和Java交互:

调用了Java中的null对象;

非空泛型被从Java中放入了null值;

其他Java中引起的空指针。

Kotlin中区分可空和不可空,例如一个不可空的String:

var a: String = "abc"
a = null // 编译报错


要使用可空类型,声明为可空字符串
String?


var b: String? = "abc"
b = null // ok


此时调用不可空类型a的成员,Kotlin可以确保不会出现NPE,可以直接调用:

val l = a.length


如果访问可空类型b的成员,由于不保证非空,直接调用编译器会报错:

val l = b.length // error: variable 'b' can be null


非空检查

可以检查b是否为null,根据两种情况分别处理:

val l = if (b != null) b.length else -1


更复杂的也可以:

if (b != null && b.length > 0) {
print("String of length ${b.length}")
} else {
print("Empty string")
}


这种检查后调用只有在b检查后不变才生效,例如一个局部变量,非空检查后立刻调用,或是一个只读的不能被重写的成员。这是因为如果是外部可更改的话,可能会在非空检查后被修改为空值。

安全调用

其次可以使用安全调用运算符
?


b?.length


在b不为null时返回b.length,为空是返回null,所以整个表达式的类型是Int?。

安全调用可以写成链式,链式调用的任意节点为空都会中断调用并返回null:

bob?.department?.head?.name


如果要在?调用中一次执行多步,可以用let函数:

val listWithNulls: List<String?> = listOf("A", null)
for (item in listWithNulls) {
item?.let { println(it) } // prints A and ignores null
}


非空调用也可以写在赋值语句左侧,这样如果要赋值的链节中有空值则中断,表达式右侧不会被调用:

// If either `person` or `person.department` is null, the function is not called:
person?.department?.head = managersPool.getManager()


Elvis运算符

假如有一个可空类型的引用r,希望在r不为空时使用,如果为空则使用默认值:

val l: Int = if (b != null) b.length else -1


对于这种if表达式的形式,有更简便的Elivis运算符
?:


val l = b?.length ?: -1


对于Elvis运算符,如果
?:
左侧的值不为null,则返回此值,如果为null则返回表达式右侧的值。

?:
右侧表达式只在左侧表达式的值为null时才会执行。

Kotlin中
throw
return
都是表达式,可以用于Elvis运算符右侧:

fun foo(node: Node): String? {
val parent = node.getParent() ?: return null
val name = node.getName() ?: throw IllegalArgumentException("name expected")
// ...
}


!!
运算符

第三种处理方式针对惯用NPE的用户。非空断言运算符
!!
可以将任何类型转换成不可空类型,如果为空则抛出NPE:

val l = b!!.length


安全类型转换

类型转换如果转换目标类型不符会抛出
ClassCastException
。使用安全类型转换可以在转换失败时返回null值:

val aInt: Int? = a as? Int


可空类型集合

filterNotNull
函数可以将可空类型集合的非空元素筛选成一个不可空类型集合:

val nullableList: List<Int?> = listOf(1, 2, null, 4)
val intList: List<Int> = nullableList.filterNotNull()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Kotlin