手记

Kotlin学习之空安全

一、空安全

Java语言中没有C/C++的指针,取而代之的是引用。在Java支持的四种数据类型(类、接口、数组、基本类型)中,类、接口和数组统称为引用类型,定义一个引用类型变量需要两个步骤:

  1. 定义一个引用类型的变量。

String s;List<String> l;
int[] n;
  1. 进行初始化(创建对象并使之前定义的引用指向这个对象)。有两种方法:

  • 用new关键字调用构造方法,创建一个新对象;

  • 使用方法出入一个对象。

s = "Hello World"; // String 类型的特殊写法,等同于调用构造方法l = new ArrayList<>(); // 使用子类型创建对象n = new int[10];

在Java中,对于没有进行初始化的引用类型变量,调用它们的实例方法或实例属性都会产生NullPointerException,也就是所谓的NPE。而这一切都发生在运行时,编译时不会报错。

Kotlin的类型系统诣在从代码中消除NullPointerException。NPE的唯一可能的原因是:

  • 显示调用throw NullPointerException();

  • 使用了下文描述的!!操作符;

  • 外部Java代码导致的;

  • 对于初始化,有一些数据不一致。

Kotlin解决空安全,而不是消灭NPE,而是允许NPE存在,但只会在它该出现的时候出现。Kotlin区分了可空类型与不可空类型。

二、可空类型与非空类型

在Kotlin中如下代码:

val s: String = null

会得到一个编译错误。编译器说不能讲null赋给非空的String类型。

在Kotlin中,所有数据类型默认都是非空的,如果想把null赋给它们的对象,需要在类型后加上?,声明为可空类型。

所以上面的代码需要在String后面加上?:

val s: String? = null

所以,在Kotlin中我们只要将变量声明为非空类型,就可以放心地调用它的实例方法和实例变量,不用担心出现NPE。

三、安全调用符(?.)

对于可空类型的变量,应该怎样安全地调用它的属性和方法呢?Kotlin的解决方式是使用?.安全调用符。

如下面Kotlin的函数:

// 安全调用属性fun printLengthOfString(s: String?) = println(s?.length)

在Java中等同于如下:

public static final void printLengthOfString(@Nullable String s) {
  Integer var1 = (s != null) ? s.length() : null;
  System.out.println(var1);
}
  • 安全调用操作符(?.)实际上是个语法糖,会被编译为一个三目运算表达式。

  • 如果?.前的对象不为null,则调用?.后的方法或属性,否则就返回null。

  • 如果一个可空变量已经被判断为非空,再次调用它的方法和变量时,会自动将变量转换为非空类型,实现安全调用。

四、Elvis操作符(?:)

这个操作符是三目条件运算符的简略写法。

如果?:左侧表达式非空,Elvis操作符就返回其左侧表达式,否则就返回右侧表达式。请注意,当且仅当左侧为空时,才会对右侧表达式求值。

Kotlin中用Elvis操作符配合安全调用符实现简单清晰的空检查和空操作。

在Java中:

(files != null) ? files.length : "Empty"

在Kotlin中:

files?.size ?: "Empty"

可以如下理解Elvis操作符:

  • A ?: B 等价于 if(A==null) B

  • A ?. B ?: C 等价于 if(A!=null) A.B else C

五、let函数

let函数可以看做一个加强版的安全操作符,或者另一种写法if not null then语句。

let函数单纯地接收一个函数,然后执行它,返回函数的执行结果。一般情况下,let函数与安全调用符配合使用:

val listWithNulls: List<String?> = listOf("A", null)for (item in listWithNulls) {
     item?.let { println(it) } // 输出 A 并忽略 null}

也就是时候安全调用符+let函数就等同于if not null then语句。

六、非空操作符(!!)

要在Kotlin中产生NPE,有两种办法:

  • 显式地throw NullPointerException();

  • 使用非空操作符!!。

val l = b!!.length

b!!会返回一个非空的b值,如果b为空,就会抛出一个NPE异常。

但是,Kotlin并不建议在代码中广泛使用!!操作符,因为这样会浪费Kotlin良好的非空类型的设计,让Kotlin代码中充斥着NPE。

原文链接:http://www.apkbus.com/blog-815579-77461.html

0人推荐
随时随地看视频
慕课网APP