Kotlin - 空安全
2017-08-08 本文已影响117人
fish_leong
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.总结
- Kotlin定义变量时,通过给变量的类型后增加?操作符,可以设置该变量是否可以接受空引用(即可赋值为null)。
var a:String?=null//可接受空引用
var b:String="fish_leong"//不可接受空引用
2.不接受空引用的变量,在IDE中编写代码阶段,IDE通过语法检查帮助我们检查出NPE错误,对该类型的变量也不需要再做null判断,相对减少了不必要的代码,同时也减少了苦逼的debug、打log的排查错误的时间,提高了效率。
3.可接受空引用的变量的两种操作方式
-
安全调用(Safe Calls)
如果该变量时可接受空引用的变量,在调用它的成员属性或成员方法时,要使用?安全调用,这样即便变量是null,也不会抛出异常,只会返回nullvar 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 - 百度百科