侧边栏壁纸
博主头像
Z同学博主等级

工作磨平激情前,坚持技术的热忱。 欢迎光临Z同学的技术小站。 分享最新的互联网知识。

  • 累计撰写 274 篇文章
  • 累计创建 55 个标签
  • 累计收到 74 条评论

Kotlin 基础-空值null状态详解,以及各种Null值判定符-一篇文章全部了解

Z同学
2021-12-29 / 0 评论 / 1 点赞 / 278 阅读 / 2,886 字
温馨提示:
本文最后更新于 2021-12-29,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

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 也可以有值
}

如果使用可空类型有以下几个限制:

  1. 不能直接调用可空类型对象的函数或者属性。必须进行验空逻辑之后才能调用。
  2. 不能把可空类型数据赋值给非空类型变量。必须进行验空逻辑之后才能调用。
  3. 不能把可空类型数据传递给非空类型入参的函数。必须进行验空逻辑后才能调用。

总而言之,即使大家都是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的各种情况又进行了一番深入介绍

1

评论区