1.介绍
我们在接触Kotlin之前,大家都应该听过一个概念。
Kotlin不会出现java的那种NullPointerException造成的崩溃。所以Kotlin是安全的。那么难道是说Kotlin不支持null值情况了么?
并不是,只是说Null状态必须明确定义了。在编译的时候就显式定义参数是否允许为null。
然后其他模块在调用的时候,也可以明确是否要进行验证了。
而java可能很多地方都在重复的冗余的验证是否为null了。否则就会出现崩溃的问题。
2.Kotlin 可空类型
在Kotlin 语言中,默认情况下所有的数据类型都是非空类型(Non-Null)初始化。默认创建的对象或者变量是不能接收空值(Null)类型的值。
如果出现了,那么在代码编写过程中,编译器就会提示错误了。这种机制有效的避免了无意之间null值的引用和传递。
这也是Kotlin的安全性的由来之一。
那么我们在Kotlin中如何处理null值需求呢?很简单,使用关键字:?
。在创建属性后面添加上问号。那么编译器就能知道你这个对象可以赋值为null了。
实例:
//错误情况
var n:Int =2021
n = null
//正常情况
var n:Int ?=2022
n = null
2.1 声明规范
通过上面的例子我们可以知道,Kotlin中声明一个对象或者接口中返回对象可能为Null的情况。是通过在变量类型后面添加?
来实现的。
下面就完整介绍一下,对象声明的时候和函数声明的时候。空值情况的定义
实例:
//定义属性是否为空
var zin:Int? =null //声明一个Int对象 ,它可以为null 也可以有值
var yan:String? =null //声明一个String对象,它可以为Null,也可以有值
//定义函数返回值是否有null
fun zinyan(n1:Int,n2:Int?):Long?{
//例如定义两个传参 n1是Int,n2可以为Int也可以为Null, 返回值是Long。而Long可为Null 也可以有值
}
如果使用可空类型有以下几个限制:
- 不能直接调用可空类型对象的函数或者属性。必须进行验空逻辑之后才能调用。
- 不能把可空类型数据赋值给非空类型变量。必须进行验空逻辑之后才能调用。
- 不能把可空类型数据传递给非空类型入参的函数。必须进行验空逻辑后才能调用。
总而言之,即使大家都是Int类型,但是一个可为空一个不可为空。那么Kotlin就不允许你进行互换转换。
那么针对Null值和非Null值之间的转换和验证需求,Kotlin提供了几种不同的运算符:
- 安全调用运算符:
?.
- 安全转换运算符:
as?
- Elvis运算符:
?:
- 非空断言符:
!!
2.2 安全调用运算符:?.
这个的使用场景是针对本身有一个数据类型为可Null类型。然后它需要赋值给不非Null类型或者,传递给非Null类型的函数时。进行的安全验证手段,这个也就是我们在前面说的显式声明。
然后Kotlin会在调用的地方判断是否为Null,如果为Null就不会执行函数调用或者属性赋值。并返回空值。否则就返回代码计算的结果。
实例:
fun zinyan(n1:Int,n2:Int):Double?{
if(n2==0){
return null
}
return n1+n2
}
fun main(args:Array<String>){
val num1 = zinyan(100,0) //因为n2 赋值为0 那么函数返回null, num1为null
val num2 = num1?.plus(100) //因为 num1为null 所以执行加法之后还是为null
println(num2)
val yan1= zinyan(100,100)
val yan2= yan1?.plus(100) //因为yan1=200 +100 = 300
println(yan2)
}
//输出
null
300
我们如果是在java中,这么写的话在num2计算的时候就会崩溃了,因为num1为null。而在Kotlin中不会出现崩溃。只是最后num2的输出结果直接为null。
2.3 安全转换运算符:as?
其实在Kotlin中是使用as
进行强制类型转换的。然后我们再添加?
实现了空值的安全转换,这也是as?
安全转换运算符的由来。避免转换过程中的崩溃异常。
例如:
fun main(args: Array<String>){
val zin: Any? = null
val yan: String = zin as String
println(yan)
}
//输出
kotlin.TypeCastException: null cannot be cast to non-null type kotlin.String
这种情况下,我们就需要as?
来解决可能出现的Exception
了。
fun main(args: Array<String>){
val location: Any = "Zinyan.com"
val str: String? = location as? String
val num: Int? = location as? Int
println(str)
println(num)
}
//输出
Zinyan.com
null
2.4 非空判断运算符:?:
有时在可空类型的表达式中当表达式的值为Null时,我们并不希望返回Null,而是返回其他值。例如0,false等等情况。这种情况下
就可以使用非空判断运算符了,也叫做空值合并运算符。
例如:A?:B如果A不为空则结果为A,否则为B(PS:其实就类似于我们在java中使用的三元运算符
?:`)
实例:
fun main(args: Array<String>) {
var age: String?=null
//得到age的值并转为Int,如果是空的话,返回-1; 可以作为判空处理逻辑
val t2 = age?.toInt() ?:-1
println(t2);
}
//输出
-1
2.5 非空断言符:!!
非Null断言符的作用就是,断言可Null数据类型的变量不会为Null。如果该对象真的为Null,会抛出空指针异常。如果是非Null,就会正常的调用函数或者属性。
实例:
fun zinyan(n1:Int,n2:Int):Double?{
if(n2==0){
return null
}
return n1+n2
}
fun main(args:Array<String>){
val num1 = zinyan(100,0) //因为n2 赋值为0 那么函数返回null, num1为null
val num2 = num1!!.plus(100) //因为 num1为null 所以执行加法之后还是为null
println(num2)
val yan1= zinyan(100,100)
val yan2= yan1!!.plus(100) //因为yan1=200 +100 = 300
println(yan2)
}
上面的结果就是会在第二步计算num2的时候报错。出现:KotlinNullPointerException错误。
这个适用于完全确定传值不为null的情况下使用。
到这里关于Null的各种情况又进行了一番深入介绍
评论区