Kotlin - 空安全

作者: fish_leong | 来源:发表于2017-08-08 13:44 被阅读117次

    1.Kotlin空安全介绍

    Kotlin空安全可消除来自代码空引用的危险。

    2.什么是空引用?

    • 许多编程语言(包括 Java)中最常见的陷阱之一是访问空引用的成员,导致空引用异常。在 Java 中, 这等同于 NullPointerException 或简称 NPE。
    • NullPointerException概述
      • NPE是java.lang.NullPointerException的简称,是Java语言中的一个异常类,位于java.lang包中,父类是java.lang.RuntimeException,该异常在源程序中可以不进行捕获和处理。
      • 什么情况下会出现空引用异常?
        • 调用 null 对象的实例方法。
        • 访问或修改 null 对象的字段。
        • 如果一个数组为null,试图用属性length获得其长度时。
        • 如果一个数组为null,试图访问或修改其中某个元素时。
        • 在需要抛出一个异常对象,而该对象为 null 时。
        • 应用程序将会抛出NullPointerException类的实例,表明其他对 null 对象的非法使用。

    3.Kotlin空安全的使用

    在 Kotlin 中,定义变量时可以决定该变量是否可以接受null(空引用)

    下面定义一个不接受空引用的变量

        var temp: String = "fish_leong"
        var length=temp.length//因为temp不接受空引用,所以它不会出现NPE,可以放心的各种. . .
        temp = null//会立刻被IDE检测出语法错误
        /***
         * Null can not be a value of a non-null type String,
         * 如果用Java写,IDE不会报错,编译也可以通过,由于代码没有进行空引用判断,最后执行必会抛出NullPointerException
         */
         println(temp.toString())
    

    以上可以看出,写代码的时候难免会有疏漏,而Kotlin在IDE中对空引用进行了检查,避免了运行时出现NPE的情况。

    下面定义一个可接受空引用的变量

    • 在定义变量类型时,在类型的后面加问号?即可,比如String?Any?
        var temp: String? = "fish_leong"//定义一个可接受空引用的变量
        val length = temp.length
        /**
         *  对上一行代码的解释
         *  这样IDE语法检查报错"Only safe(?.) or non-null assered (!!.)calls are allowed on a nullable receiver of type String?"
         *  因为temp不是空安全变量,所以不能像上面那样调用,要写成
         *  val length=temp!!.length //!! 操作符
         *  或
         *  val length=temp?.length//? 安全调用
         *  以上这两种写法的区别,在下面代码中会提到
         */
        println("temp的长度length$length")//此行输出"temp的长度length=10"
    
        // ?. 安全调用示例
        temp = null //temp可接受空引用
        val length2 = temp?.length
        /***
         * 对上一行代码的解释
         * 虽然temp是null,但这里用到了安全调用,
         * 此时temp?.length会返回一个null给length2
         */
        println("temp的长度length2=$length2")//会输出"temp的长度length2=null"
    
        println(temp?.toString())//此行输出 "null"
    
        println(temp.toString())//此行输出 "null"
        /**
         * 发现了没,上面这行代码,temp没有用空安全引用,也通过了IDE语法检查,这个在以后的文章再谈
         */
        println(temp!!.toString())//此行抛出"Exception in thread "main" kotlin.KotlinNullPointerException"异常,并终止,所以下面的代码是不能够被执行的
    
        println(temp.toString())//此行代码是将不会执行(在IDE中,也可以看到这行代码的颜色异常,它是Unreachable code(无法执行到的代码)),因为上一行代码使用了"!!"操作符,而temp又是null,所以抛出NPE终止
    

    4.总结

    1. Kotlin定义变量时,通过给变量的类型后增加?操作符,可以设置该变量是否可以接受空引用(即可赋值为null)。
          var  a:String?=null//可接受空引用
          var  b:String="fish_leong"//不可接受空引用
    

    2.不接受空引用的变量,在IDE中编写代码阶段,IDE通过语法检查帮助我们检查出NPE错误,对该类型的变量也不需要再做null判断,相对减少了不必要的代码,同时也减少了苦逼的debug、打log的排查错误的时间,提高了效率。

    3.可接受空引用的变量的两种操作方式

    • 安全调用(Safe Calls)
      如果该变量时可接受空引用的变量,在调用它的成员属性或成员方法时,要使用?安全调用,这样即便变量是null,也不会抛出异常,只会返回null

      var strB:String?=null
      var numA = strB?.toInt()// numA=null
      
    • Elvis 操作符的使用
      如果 ?: 左侧表达式非空,elvis 操作符就返回其左侧表达式,否则返回右侧表达式。 请注意,当且仅当左侧是空(null)时,才会对右侧表达式求值。

      //例1
      var strB: String? =null
      var numA = strB?.toInt()// numA=null
      println(numA)//输出 null
      numA = if (strB != null) strB?.toInt() else 1//可写作   numA = strB?.toInt() ?: 1
      println(numA)//输出 1
      

      throw 、 return、break(官方文档没写break,但在循环中使用是可以的) 在 Kotlin 中都是表达式,所以它们也可以用在 elvis 操作符右侧。

      //例2
      val arrays = arrayListOf<String?>("1", "2", null, "3")
      for (element in arrays) {
          element ?: break
          println("case one:$element")
      }
      try {
          for (element in arrays) {
              element ?: throw Exception("NPE")
              println("case two:$element")
          }
      } catch (ex: Exception) {
          println("case two exception:$ex.message")
      }
      for (element in arrays) {
          element ?: return
          println("case three:$element")
      }
      //这里就不多解释了,看输出就懂了
      

      输出

      case one:1
      case one:2
      case two:1
      case two:2
      case two exception:NPE
      case three:1
      case three:2
      
    • !!操作符(The !! Operator)

      • 也没个飘准的英文或者中文名字,看官方文档叫它"The !! Operator",!!是什么鬼,My name is !!,手动滑稽。
      • 对于需要NPE的人,就要用到这个操作符了,当一个变量使用!!时,如果该变量是null,则会抛出NPE
        val temp: String = "fish_leong";
        temp!!.length//这时编译器会提示 Unnecessary noo-null assertion(!!) on a non-null receiver of type String,因为temp声明时不接收空引用,所以在此使用!!也是多余的
      
        var temp1: String? = temp;//定义一个可接收空引用的temp1
        println("第1次$temp1!!")//使用!!,此时temp1不为null
        println("第2次$temp1")//不使用!!,此时temp1不为null
        temp1 = null
        println("第3次$temp1")//不使用!!,此时temp1为null
        println("第4次$temp1!!")//使用!!,此时temp1为null,将会抛出NPE
      

      输出

      第1次fish_leong
      第2次fish_leong
      第3次null
      Exception in thread "main" kotlin.KotlinNullPointerException
        at HelloKt.main(Hello.kt:29)
      

    参考文档:
    [1]空安全 - Kotlin 语言中文站
    [2]Null Safety - Kotlin Programming Language
    [3]NullPointerException - 百度百科

    相关文章

      网友评论

        本文标题:Kotlin - 空安全

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