Kotlin:空指针检查(补档)
Kotlin: 空指针检查(补档)
*空指针异常是Android系统上崩溃率最高的异常类型。
可空类型系统
Kotlin利用编译时判空检查的机制几乎杜绝了所有空指针异常。
分析一段Java代码:
1 | public void doStudy(Study study) { |
如果向doStudy()方法传入一个Null参数,则会发生空指针异常,因此要在调用参数的方法之前进行一个判空处理,如下代码:
1 | public void doStudy(Study study) { |
这样,就避免了此方法中的空指针错误。
如果在Kotlin中重写上述的第一段代码:
1 | fun doStudy(study : Study) { |
那么这段代码是没有空指针风险的,因为Kotlin默认所有的参数和变量都不可为空。Kotlin将空指针异常的检查提前到了编译时期。如果程序中存在出现空指针异常的风险,Kotlin则会在编译时报错,修正之后才能成功运行。
考虑到某些方法在设置的时候就是需要传入空值的,Kotlin提供了另一种可空类型的写法:在类名的后面加上一个“?”。Int表示不可为空的整形,而Int?就表示可为空的整形。String表示不可为空的字符串,String?则表示可为空的字符串。对于刚才的代码,如果我们希望传入的参数可以为空,那么就应该在Study的后面加上"?",代码如下:
1 | fun doStudy(study : Study?) { |
如上编写doStudy方法,我们就可以在调用其时向其中传入空参数:
1 | fun main() { |
此时程序便不会报错。
然而,在doStudy函数中调用参数的readBooks()和doHomework()方法时,出现了红色下划线错误提示。原因是由于参数为可空的Study?类型,此时readBooks()和doHomework()都可能出现空指针异常。因此,需要将空指针异常都处理掉:
1 | fun doStudy(study : Study?) { |
如此,便可以避免空指针错误。
由于在程序中如此编写if判断语句来进行空指针的检查会比较麻烦,Kotlin提供了一系列的判空辅助工具
Kotlin中的判空辅助工具
?.操作符
含义:当对象不为空的时候调用相应的方法,当对象为空时则什么都不做
如下代码:
1 | if (a != null) { |
这段代码可以使用?.操作符简化如下:
1 | a?.doSomething() |
用?.操作符对doStudy()方法进行优化,代码如下:
1 | fun doStudy(study : Study?) { |
?:操作符
含义:该操作符左右两边都接收一个表达式,如果左面表达式的结果不为空就返回左面表达式的结果,否则就返回右边表达式的结果。
观察如下代码:
1 | val c = if (a != null) { |
这段代码用?:操作符可以简化为:
1 | val c = a ?: b |
使用?.及?:简化一段代码:
编写一个函数,用来获得一段文本的长度
1 | fun getTextLength(text : String?) : Int { |
简化后:
1 | fun getTextLength(text : String?) = test?.length ?: 0 |
非空断言
Kotlin的判空机制并非那么只能。在某些情况下即使已经在逻辑上避免了空指针异常,编译器仍会报错,因此需要用到非空断言工具,写法是在对象的后面加上!!,如下代码:
1 | fun printUpperCase() { |
let工具
let是一个函数,这个函数提供了函数式API的编程接口,并将原始调用对象作为参数传递到Lambda表达式中,如下实例代码:
1 | obj.let { obj2 - > |
这里调用了obj对象的let函数,然后Lambda表达式中的代码就会立即执行,并且这个obj对象本身还会作为参数传递到Lambda表达式中。在上述代码中,obj2和obj是同一个对象。
用let工具优化代码:
1 | fun doStudy(study : Study?) { |
注:let函数是可以处理全局变量的判空问题的,而if判断语句则无法做到这一点。