一、可空类型系统
Kotlin默认所有的参数和变量都不可为空。
Int 表示不可为空的整型
Int? 表示可为空的整型
eg:
fun doStudy(study: Study?) {
if (study != null) {
study.doHomeWork()
study.readBook()
}
}
有点啰嗦吧,别急,Kotlin还提供了一系列辅助工具帮我们作判空处理。
二、判空辅助工具
1. ?.操作符
表示当对象不为空的时候正常调用相应的方法,当对象为空的时候什么都不做。
使用 ?.操作符改变上面代码:
fun doStudy(study: Study?) {
study?.doHomeWork()
study?.readBook()
}
2. ?:操作符
这个操作符左右两边都接收一个表达式,如果左边的表达式的结果不为空就返回左边表达式的结果,否则就返回右边表达式的结果。
//原代码
var c = if (a != nul) a else b
//使用?:操作符
var c = a ?: b
3. !!操作符
Kotlin也不是特别的智能,有时候我们逻辑上已经将空指针异常处理了,单Kotlin编译器并不知道,那么这个时候还是会编译失败,比如以下例子:
var content: String? = "hello"
fun main() {
if (content != null) {
printUpperCase()
}
}
fun printUpperCase() {
val toUpperCase = content.toUpperCase()
print(toUpperCase)
}
这段代码逻辑没问题,但是一定无法执行。因为printUpperCase()函数并不知道外部已经对content做了非空检查,所以在调用toUpperCase()时,还认为存在空指针方风险。
使用!!操作符:
fun printUpperCase() {
val toUpperCase = content!!.toUpperCase()
print(toUpperCase)
}
这是一个种有风险的写法,意在告诉Kotlin,我非常确信这里的对象不会是空,所以不用你来做非空检查了,如果出现问题,可以直接抛出空指针异常,后果我自己承担。
4. let函数
let既不是操作符也不是关键字,是一种函数。这个函数提供了函数式API的编程接口,并将原始调用对象作为参数传递到lambda表达式中,示例代码:
obj.let { obj2 ->
//编写具体的业务逻辑
}
obj与obj2是一个对象。
let函数配合?.操作符做空检查:
fun doStudy(study: Study?) {
study?.let { stu ->
stu.readBook()
stu.doHomeWork()
}
}
这样我们对study对象只做了一次非空判断就可以使用了。
优化之后:
fun doStudy(study: Study?) {
study?.let {
it.readBook()
it.doHomeWork()
}
}
另外,let函数是可以处理全局变量的判空问题的。而if无法做到这一点。