
6.2.2 使用可空类型
非空类型有一个可空的对应类型。如果类型是一个非空引用,则只能传递非空的有效引用。但是,你可以将有效引用或null传递给可空的引用类型。在接收端,如果不首先执行null检查,就不能使用由可空引用保存的对象。
可空类型有一个?后缀——也就是说,对应的非空字符串是String?。同样,Int对应Int? List<String>对应List<String>?,YourOwnClass对应YourOwnClass?。
可空类型到字节码的映射
你可能想知道可空类型是如何映射到Java字节码的,因为它们在JVM上没有直接的表示。可空类型可以清除为它的非空对应项,例如,String?变为String,以及字节码中的额外元指令。Kotlin编译器使用这些元指令来执行编译时null检查,而没有运行时性能开销。
让我们逐个修复前一段代码中的问题,从尽可能安全地返回null开始。为了表示可以从nickName()函数中返回引用或null,必须将函数的返回类型从String改为可空的对应项String?。这是修复编译错误的唯一更改:

由于传递null的最后一行被注释掉,因此代码将毫无问题的运行,并生成以下输出:

这几乎很好,为了记录起见,相信我,null不是Venkat的昵称。如果不是仅打印出响应,而是对它进行了一些处理,那么Kotlin需要对响应进行null检查。我们不去尝试在响应上做更多的工作,而是修改代码以允许将null作为参数的实参。这将帮助你学习如何处理可空引用,同时保持示例简短。
让我们对nickName()函数进行改进。在新的形式中,函数将返回"William"的正确昵称、任何其他非空名称的反向名称,对null参数返回null。为此,我们必须将参数类型从String改为String?,以便允许null参数。

在代码的最后一行传递null没有问题。但是在函数中,对name调用reversed()的那一行将编译失败。Kotlin要求对可空引用的方法调用以安全调用运算符或非空断言运算符为前缀——我们将很快看到这些运算符。编译器坚持这样做,是因为在这个例子中,name可能是null,对空引用调用一个方法会……你知道的。编译器很乐意保护我们免受运行时可能面临的厄运。谢谢你Kotlin。
在访问可空引用所保存的对象之前,必须执行null检查,如下所示:

Kotlin推动我们走上安全和防御性编程的道路。对于可空类型,我们不能忘记要执行null检查。这几乎是安全的——很快就会看到警告。让我们运行带有null检查修改的代码,并查看输出:

这是可行的,但是带有null检查的代码是混乱的。接下来,我们将看到如何既保持安全,又去掉混乱。