前言:不走心的努力,都是敷衍你自己。你要坚信现在所有过不去的坎,将来总有一天会当笑话说出来。
一、概述
Java 中定义一个变量可以默认不赋值,因为系统默认会赋值一个默认值,并且可以定义一个为 null
的变量,这样在使用的时候就需要判断该变量是否为 null
。从代码的简洁性以及代码的可读性来说,Kotlin 能更好处理,那么 Kotlin 定义一个可为 null
的变量怎么定义呢?
Kotlin 的空安全设计对于声明可为空的参数,在使用时需要做空判断处理,有两种处理方式,一是字段后面加!!
符号,像 Java 那样抛出空异常,二是字段后面加?
符号可不做处理返回值为null
或者配合?:
做空判断处理。下面针对 Kotlin 这一特性来详细讲解。
二、可空类型:?
在变量类型后面加?
符号,表示该变量为可空类型;类型后面没有加?
符号,表示该变量为不可空类型。可空变量在使用时需要做空判断处理,不可空类型变量则不需做空判断处理,因为没有意义。
定义一个可空变量的格式:
修饰符 变量名:类型? = 初始值
不可空变量:
修饰符 变量名:类型 = 初始值
因为类中的变量必须要初始化值:
- 1.如果没有声明类型,系统会自动识别你赋值的类型,如果赋值为
null
,则系统自动声明为Nothing?
,该变量值只能为null
,不能重新赋值为其他类型值; - 2.如果声明类型,但是类型后没有
?
,则表示该变量不可以为null
,在使用时不需要做空判断; - 3.如果声明类型,类型后加
?
,表示该变量可为null
,如:Int?
,在使用时需要做空判断。
//1.不可空类型并且初始化值为null
var numA = null //没有声明类型,初始化值为null,不能重新赋值其他类型值
//numA = 10 报错
//numA = "文字" 报错
//2.不可空类型并且初始化值不为null
var numB: Int = 15
//numB = null 报错,类型没有‘?’,不能赋值为null
numB = 0 //可以赋值Int类型的值
if (numB != null) {//numB声明不为null,这个判断没有意义
}
//3.可空类型
var numC: String? = null//该变量可以为String类型的值和 null
numC = "HelloWord"
if (numC != null) {//可空类型,使用时需要做空判断处理
}
我们看下方法参数和返回值可空和不可空的使用:
fun setType(type: Int?) {//表示参数type可以为空
}
fun setType(type: Int) {//表示参数type不可以为空
}
fun getName(): String? {//表示返回的值可以为空
return null
}
fun getName(): String {//表示返回的值不可以为空
return "名字"
}
三、安全调用运算符:?.
安全调用运算符?.
用于可空类型变量安全调用非空类型的属性或者函数,而不会抛出空指针异常,当变量为null
时,直接返回空值null
,否则进行调用并返回结果。
3.2 if…else
在上面我们提到可空类型的使用是需要判断的,Kotlin 中可以if…else
来判断是否为空:
var user: User? = null
if (user == null) {
} else {
}
3.2 安全调用运算符
也可以使用安全运算符?.
来判断是否为空,如果可空类型变量为null
时怎返回null
,格式如下:
可空类型变量?.属性/方法名
表示当变量user为null
时,依然执行user?.name
语句,不会报错,返回一个null
值。
var user: User? = null
//user为null,获取返回的数据都为null
Log.e(TAG, "安全调用运算符:user == name:${user?.name} | age: ${user?.age}| sex: ${user?.sex}")
打印数据如下:
安全调用运算符:user == name:null | age: null| sex: null
3.3 链式调用
链式调用能大量避免空指针异常NullPointException
,因为链式整只有一个为null
,则整个链式返回值就为null
。
var user: User? = null
var address = user?.info?.address//链式调用获取user里面的info的address
Log.e(TAG, "安全调用运算符:address == $address")
打印数据如下:
安全调用运算符:address == null
3.4 let函数
使用let
函数,避免写一些判断null
的操作,当你需要定义一个变量在一个特定的作用域范围内,let
函数更适合,它实际是一个作用域函数。使用格式如下:
//判断object为null的操作
object?.let{//表示object不为null的条件下,才会去执行let函数体
it.todo()
···
}
在代码块内可以通过it替代该对象,即it
就是user:
var user: User? = null
user?.let {//it表示user,如果user为null,let函数不会被执行
var name = it.name
var age = it.age
var sex = it.sex
}
当然其他作用域函数with,run,apply,also等也适用
四、Elvis运算符(空值合并运算符):?:
?:
是一个二元运算符,作用是判断可空类型时空值合并,语法为:可空类型数据 ?: 空值合并到的数据
,Kotlin 中不存在三目运算符。当数据非空时,直接返回数据,当数据为空时,返回合并到的数据。利用该运算,能很好把可空类型转为非空类型。
判断一个可空类型时,如果返回数据不为空时,则返回当前数据;如果返回数据为空时,则返回一个设定好的默认值。
var length = 0
var strA: String? = "HelloWord"
//传统判断
length = if (strA != null) strA.length else -1
Log.e(TAG, "空值合并运算符 strA不为null:length == $length")
//空值合并运算符?:
strA = null
length = strA?.length ?: -1//如果strA?.length为null则返回-1,否则返回strA?.length
Log.e(TAG, "空值合并运算符 strA为null:length == $length")
其实if (strA != null) strA.length else -1
等价于 strA?.length ?: -1
,打印数据如下:
空值合并运算符 strA不为null:length == 9
空值合并运算符 strA为null:length == -1
五、非空断言运算符:!!
非空断言运算符用于断言一个可空各类型变量,如果该变量为null
,则会抛出空指针异常kotlin.KotlinNullPointerException
。!!
方便爱好抛出空指针异常的开发者使用,在一个可空变量后面加上!!
,如果变量为null
,运行时会抛出空指针异常。
//1.变量不为`null`
var name: String? = "HelloWord"
Log.e(TAG, "非空断言运算符:length == ${name!!.length}")
//2.变量为`null`
name = null
val user = User(name!!, 10, "性别")//运行异常,抛出空指针异常
Log.e(TAG, "非空断言运算符:length == ${user?.name}")
可以看到当name != null
时,正常运行:
非空断言运算符:length == 9
当name == null
时,name!!
抛出空指针异常。
在最新版的 Kotlin 中,如果检查了变量非空,则直接调用非空类型的属性和函数时不需要!!
。
六、安全转换运算符:as?
在 Kotlin 中使用as
进行类型的强制转换,as?
表示类型的安全转换。如果as
进行类型转换不能正常转换的话会抛出类型转换异常ClassCastException
,而as?
则会返回 null
,不会抛出异常。
6.1 as
的使用
var num: Int? = "Kotlin" as Int//抛出类型转换异常
String
类型无法转换成Int
类型,as
进行类型转换是不能正常转换,抛出异常。
6.2 as?
的使用
使用as?
进行安全转换,当需要转换的数据为null
时,返回null
,不抛出异常;当需要转换的类型不一致时,也是返回null
,不抛出异常。
var str: String? = null
var num = str as? Int
Log.e(TAG, "安全转换运算符:num == $num")
str = "Android"
num = str as? Int
Log.e(TAG, "安全转换运算符:num == $num")
打印数据如下:
安全转换运算符:num == null
安全转换运算符:num == null
总结一下上面几种运算符:
运算符 | 符号 | 含义 | 例子 |
可空类型 | ? | 在变量类型后面加 |
|
安全调用运算符 | ?. | 可空类型变量安全调用非空类型的属性或者函数,而不会抛出空指针异常, 当变量为 |
|
空值合并运算符 | ?: | 判断可空类型,如果数据为 |
|
非空断言运算符 | !! | 断言一个可空各类型变量,如果该变量为 |
|
安全转换运算符 | as? | 类型安全转换,转换不成功则返回 |
|
源码地址:https://github.com/FollowExcellence/KotlinDemo-master
点关注,不迷路