美文网首页
Kotlin之空指针检查以及Kotlin中的小魔术

Kotlin之空指针检查以及Kotlin中的小魔术

作者: code希必地 | 来源:发表于2020-09-21 11:32 被阅读0次

1、可空类型系统

Kotlin在编译时判空检查的机制几乎杜绝了空指针异常,虽然编译时判空机制有时候会导致代码变得比较难写,但是Kotlin提供了一系列辅助工具,让我们能轻松处理各种判空情况。
先看下面这个方法

 fun doStudy(study : Study){
        study.doHomeWork()
    }

Kotlin默认所有的参数和变量都不可为空,所以这里传入的study一定不为空,如果你尝试向doStudy()方法中传入null

image.png
可以看到,Kotlin将空指针异常提前到了编译期间,如果我们的程序存在空指针异常,那么在编译时就报错。那如果我们业务逻辑需要变量为空,该怎么办呢?很简单,直接在类名的后面加上?即可
image.png
可以看到在调用doStudy()方法时可以传入null了,但是使用study调用方法doHomeWork()方法时却又编译失败了,其实很简单由于我们在传入的参数可能为空了,所以在调用方法时就可能会有空指针的风险。此时,我们就需要增加一个判断了。
fun doStudy(study: Study?) {
        if (study != null)
            study.doHomeWork()
    }

但是在编译时期就处理掉所有的空指针异常,通常需要编写很多额外的代码检查才行,如果每处检查代码都是用if判断就比较啰嗦,而且if判断还处理不了全局变量判空的问题,为此Kotlin提供了一些列的辅助工具。

2、判空辅助工具

2.1、?.操作符

?.操作符表示不为空则调用相应的方法,如果为空则什么都不做。
将有if判断的代码简化如下:

fun doStudy(study: Study?) {
        if (study != null)
            study.doHomeWork()
        //使用?.替代if判断
        study?.doHomeWork()
    }

2.2、?:操作符

?:操作符两边都接收一个表达式,如果左边表达式不为空则返回左边表达式,否则就返回右边的表达式结果。

  val c = if (a != null) {
            a
        } else {
            b
        }
//使用?:简化为
val c = a ?: b

接下来我们通过一个具体的例子来结合?.?:来加深其理解,比如我们编写一个函数用来获取文本的长度。传统的写法如下:

 fun getTextLength(text: String?): Int {
        if (text != null)
            return text.length
        else
            return 0
    }

我们可以使用辅助操作符让它变得更简单

fun getTextLength(text: String?) = text?.length ?: 0

text?.lenght在text为null时是不调用text.length方法的,其返回值为null,而text?.length作为?:左边的表达式在text为null时其值为null,所以返回0,在左边的表达式不为null时返回左边表达式的值即text.lenght的值。

2.3、!! 非空断言工具

不过Kotlin的空指针检查机制并不是完全靠谱,有时候我们在逻辑上已经将空指针异常处理了,但是编译依然失败,看下面的例子。

val content: String? = "hello"

    fun main(){
        if(content!=null)
            printUpperCase()
    }

    fun printUpperCase(){
        println(content.toUpperCase())
    }

我们定义的可为空的全局变量content,然后在main()中做了非空的判断,但是在printUpperCase()中调用content.toUpperCase()还认为这里存在空指针风险,所以编译失败。
在这种情况,如果我们想强行编译通过,可以使用非空断言工具,在对象后面加上!!

 fun printUpperCase() {
        println(content!!.toUpperCase())
    }

注意:非空断言是一个有风险的操作 ,意在告诉Kotlin这里肯定不为空,所以你不用来做空指针检查了,如果出现问题直接抛出空指针异常。

2.4、let函数

let不是一个操作符也不是一个关键字,而是一个标准的函数,这个函数提供了函数式API的编程接口,并将原始对象作为参数传递到Lambda表达式中,实例如下:

obj.let { obj2->
    //编写具体的逻辑
}

可以看到obj调用let函数时,代码逻辑会立即执行并将obj对象本身作为参数传递到Lambda表达式中,这里命名为obj2只是为了防止重名,其实obj2就是obj对象。
下面我们看下函数let和空指针检查的关系。先看下面的代码:

 fun doStudy(study: Study?) {
        study?.doHomeWork()
        study?.readBook()
    }

将其转换成Java代码

fun doStudy(study: Study?) {
        if(study!=null)
            study.doHomeWork()
        if(study!=null)
            study.readBook()
    }

可以看到我们对study做了两次判断,其实我们只需要判断一次就行了,这里就用到了let函数了

fun doStudy(study: Study?) {
        study?.let { stu ->
            stu.doHomeWork()
            stu.readBook()
        }
    }

study不为null时会调用let函数,然后将study传递到Lambda表达式中,此时study肯定不为空了就能放心使用了。
还记得Lambda表达式的语法特性吗?当只要一个参数时可以不用声明参数及类型并用it代替。

fun doStudy(study: Study?) {
        study?.let {
            it.doHomeWork()
            it.readBook()
        }
    }

let函数可以处理全局变量的判空处理,但是if判断是无法对全局变量进行判空

image.png
从上图可以看出,报错的原因呢是:study是可变属性,此时可能已经被更改(被其他线程修改),如果生命的全局变量是用val修饰的是没问题的。

相关文章

  • Kotlin之空指针检查以及Kotlin中的小魔术

    1、可空类型系统 Kotlin在编译时判空检查的机制几乎杜绝了空指针异常,虽然编译时判空机制有时候会导致代码变得比...

  • Kotlin-空指针检查

    Kotlin搞空指针检查现象:java存在问题,大量的崩溃是空指针异常。原因:java的空指针异常是一种运行时异常...

  • Kotlin笔记 空指针检查

    Kotlin相较于java的一大优势就是可以减少空指针的出现,变量的type需要指定是否能为空,不带?的type不...

  • Kotlin-空指针检查

    1、空指针异常是一种不受编程语言检查的运行时异常,只能由程序员主动通过逻辑判断来避免。 1.1、调用参数的方法之前...

  • Kotlin基础(8)-->空指针检查

    一、可空类型系统 Kotlin默认所有的参数和变量都不可为空。Int 表示不可为空的整型Int? 表示可为空的...

  • Kevin Learn Kotlin:空指针检查

    可空类型 当我们在声明方法时,如果允许在这个方法被调用的时候传给它 null 的实参,则需要显示地 在类型名称后面...

  • Kotlin 空指针

    针对空指针问题, Kotlin有专门的针对语法以避免问题。 可空类型 默认声明的变量是不能为 null 的,如果要...

  • Android应用常见Crash与对策(Kotlin)

    Crash原因 NullPointerException:Kotlin语法上控制空指针 IndexOutOfBou...

  • null安全与异常

    null 在Java中我们常见的空指针异常NullPointerException,带给我们很多麻烦。Kotlin...

  • Kotlin学习之继承

    Kotlin学习之继承 @(Kotlin学习) Kotlin中的继承模式与Java中存在差异: Kotlin中所有...

网友评论

      本文标题:Kotlin之空指针检查以及Kotlin中的小魔术

      本文链接:https://www.haomeiwen.com/subject/yjqmyktx.html