Java中常见的错误就是访问空引用的成员变量,导致空引用异常,就是我们 常说的空指针异常 – NullPointerException(简称为NPE)
.
1. Kotlin 可空类型和非空类型
Kotlin 声明一个对象 可为 null ,则声明如下:
val object: Any ?= null
Kotlin 声明一个对象 不可为 null ,则声明如下:
val object: Any = Object()
以下为具体事例:
var a:String?="abc"
a=null;//编译可用过
栗子2:
var b:String="abc"
b=null;//编译错误
原因:因为变量b在声明时没有指明可以为 null
的属性
同理: 在我们访问一个变量 a(为可以为空的类型)的属性或者方法时,应该保证 其不会造成 NPE
;
val l=a.length()//编译错误
原因:变量 a 可能会是 null,
但是访问变量 b 的相同方法,则不会出现这个问题
val l=b.length()//因为变量b不可为空
2. 使用条件语句检测是否为 null
场景:判断变量 b 是否为空,我们可以有两种选择:
a:
val l=if(b!=null)b.length else -1
b:
if (b != null && b.length > 0)
print("String of length ${b.length}")
else
print("Empty string")
注意事项:
需要注意的是变量 b 为不可变量,不然会检测为空从而导致异常。
3. 安全的调用
1. 基本介绍
安全操作符 ?.
表达式: b?.length
表示的意义:若 b 为非空变量,就会返回 b.length,否则就返回 null。
完整表达式:
var a:Int?=b?.length
由于 b?.length
存在可能返回 null 的情况,所以变量 a
的声明类型为 Int?
。
2. 运用在链式调用
安全调用是十分有用的。
如果 Bob,一个雇员,可被分配给一个部门(或不),这反过来又可以获得 Bob 的部门负责人的名字(如果有的话),我们这么写:
var name: String? = bob?.department?.head?.name
如果任意一个属性(环节)为空,这个链式调用就会返回 null
同理 name 也要声明为 String?
。
4. Elvis操作符 ?:
我们有一个可以为 null 的变量,其操作的场景为如果该变量为非空时,我们使用它 (操作该变量的属性或者方法);否则使用一个非空的值:
val l:Int=if(b!=null) b.length else -1
对于完整的IF表达式,我们可以换成 Elvis 操作符进行表示:
val l:Int=b?.length?:-1
具体表达的含义:
如果 ?:
左边的表达式为非空时,Elvis 操作符就会返回左边的结果,否则返回右边的内容。
注意此时 ?:
的左侧也可以为具体的对象,并不是只能为表达式。
因为 throw
和 return
在 Kotlin 中都是一种表达式,它们也可以用在 Elvis 操作符的右边。非常方便,例如,检查函数参数:
fun foo(node: Node): String? {
val parent = node.getParent() ?: return null
val name = node.getName() ?: throw IllegalArgumentException("name expected")
// ...
}
5. 操作符 !!
我们可以写成 b!!
,b
就为一个非 null 的变量,如果 b
为空,就会抛出 NPE
异常。
val l:Int=a!!.length()
6. 安全转型 as?
转型的时候,可能会经常出现 ClassCastException
。 所以,现在可以使用安全转型,当转型不成功的时候,它会返回 null:
val aInt: Int? = a as? Int