本文借鉴自第一行代码 (第三版)
Test类:
class Test{
fun a(){
println("调用a方法")
}
}
写一个用该类对象作参数的方法
fun doSomething(a: Test){
println(a.a())
}
此时就会出现一个问题: 当参数为null时候会报红. 如下
这是因为kotlin默认所有的参数和变量都不可为空
那么问题又来了, 有时候参数需要为空怎么办? 对doSomething
方法作如下修改
fun doSomething(a: Test?){
println(a.a())
}
可以看到在参数类名后多了一个?
, 这时该参数就表示为: 我希望传入的参数可以为空
那么问题又来了, 因为doSomething里的a方法爆红了, 如下
原因在于当参数为可空类型时, 调用该参数的方法都可能造成空指针异常, 在这种条件下Kotlin不允许编译通过
那么我们只需在调用前判断a是否为空就行. 对doSomething作如下修改
fun doSomething(a: Test?){
if (a != null) {
println(a.a())
}
}
那么问题又来了, 每个方法都要这样判断是否麻烦
对此, Kotlin提供了判空辅助工具
辅助判空工具
- ?.
一个问号一个点, 该操作符就相当于doSomething的if判空
对doSomething作如下修改
fun doSomething(a: Test?){
println(a?.a())
}
ok 没有报红
- ?:
该操作符左右两边接收一个表达式, 若左表达式的结果不为空就返回左边的结果, 反之返回右边的结果
举个例子
fun ke(a: String?): Int = a?.length ?: 0
- !!
可以看到在一个类里定义实例变量text, 在main函数内先判空, 若不为空调用bs方法, 但是报红了. 这是因为bs方法不知道外部已经进行判空检查, 故认为这里存在空指针风险. 若想通过编译就可以使用!!
操作符了. 该操作符表示为: 我确信这里的对象不为空, 你就不用做空指针检查了, 出现问题了后果我自己承担 - let函数
把Test类新增一个b方法, 在doSomething中修改如下
fun doSomething(a: Test?){
println(a?.a())
println(a?.b())
}
将该方法转换成Java代码
可以看到该方法内进行了两次对a的判空, 此时就可以使用let函数
进行优化了
let函数的语法如下
obj.let{ a ->
//具体逻辑
}
其中obj为对象, a为lambda参数, 实际上obj和a为同一对象, 此时doSomething方法就可以作如下修改
fun doSomething(a: Test?){
a?.let { x ->
println(x.a())
println(x.b())
}
}
由于lambda参数列表只有一个参数 (x), 可以不用声明参数名, 直接用it
代替
fun doSomething(a: Test?){
a?.let {
println(it.a())
println(it.b())
}
}
基本上这就是Kotlin的空指针检查了