Kotlin学习3-null安全与异常处理

322 阅读4分钟

null安全与异常处理

1、null

  • 在Java中我们司空见惯的空指针异常NullPointerException,带给了我们很多麻烦。Kotlin作为更强大的语言,势必会基于以往的语言设计经验对其进行改良。Kotlin更多的把运行时可能会出现的null问题,以编译时错误的方式,提前在编译期强迫我们重视起来,而不是等到运行时报错,防范于未然,提高了我们程序的健壮性。

2、可空性

  • 对于null值问题,Kotlin反其道而行之,除非另有规定,变量不可为null值,这样一来,运行时崩溃从根源上得到解决。

3、Kotlin的null类型

  • 为了避免NullPointerException,Kotlin的做法是不让我们给非空类型变量赋null值,但null在Kotlin中依然存在
fun main() {
    //?可空字符串类型
    var str: String? = "asdf"
    str = null
}

4、null安全

  • Kotlin区分可空类型和非可空类型,所以,你要一个可空类型变量运行,而它又可能不存在,对于这种潜在危险,编译器时刻警惕着。为了应对这种风险,Kotlin不允许你在可空类型值上调用函数,除非你主动接手安全管理

4.1选项一:安全调用操作符

  • 这次Kotlin不报错了,编译器看到有安全调用操作符,所以它知道如何检查null值。如果遇到null值,它就跳过函数调用,而不是返回null。
fun main() {
    var str: String? = "asdf"
    str = null
    //?安全检查,当为null时,就不调用这个函数
    str?.capitalize()
}

4.2使用带let的安全调用

  • 安全调用允许在可空类型上调用函数,但是如果还想做点额外的事,比如创建新值,或判断不为null就调用其他函数,怎么办?可以使用带let的安全调用操作符。你可以在任何类型上调用let函数,它的主要作用是让你在指定的作用域内定义一个或多个变量。
  • let函数返回lambda表达式最后一行的结果
fun main() {
    var str: String? = "asdf"
    str = ""
    //let不论str是否为null都会进行let,在let中可以进行各种判断
    str = str?.let {
        if (it.isNotBlank()) {
            it.capitalize()
        } else {
            "Butterfly"
        }
    }
    println(str)
}

4.3选项二:使用非空断言操作符

  • !!又称叹号操作符,当变量值为null时,会抛出KotlinNullPointerException。
fun main() {
    var str: String? = null
    str = str!!.capitalize()
    println(str)
}

4.4选项三:使用if判断null值的情况

  • 我们也可以使用if判断,但是相比之下安全调用操作符用起来更灵活,代码也更简洁,我们可以用安全操作符进行多个函数的链式调用。
fun main() {
    var str: String? = null
    if (str != null) {
        str = str.capitalize()
    } else {
        println("为null")
    }
}

4.5使用空合并操作符

  • ?:操作符的意思是,如果左边的求值结果为nul,就使用右边的结果值
fun main() {
    var str = "asdf"
    str = str ?: "butterfly"
}
  • 空合并操作符也可以和let函数一起使用来替代if/else语句
fun main() {
    var str: String? = null
    str = str?.let { it.capitalize() } ?: "butterfly"
}

5.异常

  • 抛出异常
  • 自定义异常
  • 异常处理
fun main() {
    val number: Int? = null
    try {
        number!!.plus(1)
    } catch (e: Exception) {
        println(e)
    }
}
fun main() {
    val number: Int? = null
    try {
        checkOpt(number)
        number!!.plus(1)
    } catch (e: Exception) {
        println(e)
    }
}

fun checkOpt(number: Int?) {
    number ?: throw UnskilledException()
}

//自定义异常
class UnskilledException() : IllegalArgumentException("操作不当")

6.先决条件函数

  • Kotlin标准库提供了一些遍历函数,使用这些内置函数,你可以抛出带自定义信息的异常,这些便利函数叫做先决条件函数,你可以用它定义先决条件,条件必须满足,目标代码才能执行。

    1. checkNotNull:如果参数为null,则抛出IllegalStateException异常,否则返回非null值
    2. require:如果参数为false,则抛出IllegalArgumentException异常
    3. requireNotNull:如果参数为null,则抛出IllegalStateException异常,否则返回非null值
    4. error:如果参数为null,则抛出IllegalStateException异常并输出错误信息,否则返回非null值
    5. assert:如果参数为false,则抛出AssertError异常,并打上断言编译器标记
fun main() {
    val number: Int? = null
    try {
        checkOpt(number)
        number!!.plus(1)
    } catch (e: Exception) {
        println(e)
    }
}

fun checkOpt(number: Int?) {
    checkNotNull(number, { "Something is not good" })
}