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

空安全

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中throwreturn都是表达式,可以用于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()
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值