赞
踩
可空性是 Kotlin 类型系统中帮助你避免 NullPointerException 错误的特性。 作为一个程序的用户,你很可能见过像这样干巴巴的错误信息“An error has occurred: java.lang.NullPointerException”(发生了错误 : java.lang.NullPointerException)。 这条信息还有另外一个版本“Unfortunately, the application X has stopped”(对不起, X 应 用程序己停止),其背后的隐藏原因往往也是 NullPointerException。这样的 错误让用户和开发者都觉得庆烦。
现代编程语言包括 Koti in 解决这类问题的方法是把运行时的错误转变成编译期 的错误。通过支持作为类型系统的一部分的可空性,编译器就能在编译期发现很多 潜在的错误,从而减少运行时抛出异常的可能性。
Kotlin 和 Java 的类型系统之间第一条也可能是最重要的一条区别是, Kotlin 对可空类型的显式的支持。这意味着什么呢?这是一种指出你的程序中哪些变量和属 性允许为 null 的方式。如果一个变量可以为 null,对变量的方法的调用就是不安全的,因为这样会导致 NullPointerException。 Kotlin 不允许这样的调用, 因而可以阻止许多可能的异常
fun strLen(s: String) = s.length
strLen(null)
如上面的代码和调用是会报Error的。
ERROR: Null can not be a value of a non-null type String
在kotlin中我们用“问号 ?”来表示可空
type? = type or null
问号加在任何类型的后面表示这个类型的变量可以存储Null引用。
重申一下,没有问号的类型表示这种类型的变量不能存储null引用,这说明所有常见类型默认都是非空的。除非显式的把它标记为可空。
还是上面的代码,如果加上“问号?” 支持可空类型
fun strLen(s: String?) = s.length
因为s支持null的引用,这个时候s.length是会报异常的。所以这行代码会有Error提示
ERROR: only safe (?) or non null asserted (! !.) calls are allowed on a nullable receiver of type kotlin.String?
所以正确的写法应该是
fun strLenSafa(s: String?): Int = if(s != null) s.length else 0
增加了null引用的判断就不会有问题了。
可以说是Kotlin中最有效的一种安全调用运算符,它允许你把一次null检查和一次方法调用合并成一个操作
s?.toUpperCase() 等同于下面的写法:
if(s != null) s.toUpperCase() esle null
换句话说如果你试图调用一个非空的方法,这次方法调用会被正常执行,但是如果值是null,这次调用不会发生,二整个表达式的值为null
fun strLen1(s: String?) = s?.length
类似于这种写法,当s不为空的时候 返回的是一个int长度,但是当为空的时候并不会返回一个0,而是null
class Address(val streetAddress: String, val zipCode: Int, val city: String, val country: String)
class Company(val name: String, val address: Address?)
class Person1(val name: String, val company: Company?)
fun printShippingLabel(person: Person1) {
val address = person.company?.address ?: throw IllegalArgumentException("No Address")
with(address) {
println(streetAddress)
println("$zipCode $city, $country")
}
}
带null检查的方法调用序列在java中太常见了。类似于上面的这种,kotlin可以让他们变得更加简洁。
kotlin有更方便的运算符来提供null的默认值
fun foo(s: String?) {
val t: String = s ?: ""
println("zifu:" + t)
}
如果s为null,结果就是一个空字符串
Elvis 运算符接收两个运算数,如果第一个运算数不为 null,运算结果就是第 一个运算数;如果第一个运算数为 null,运算结果就是第二个运算数。
fun strLengthSafe(s: String): Int = s?.length ?: 0
as 运算符。和 常规的 Java 类型转换一样,如果被转换的值不是你试图转换的类型,就会抛出 ClassCastException 异常。当然可以结合 is 检查来确保这个值拥有合适的类型。 但是作为一种安全简洁的语言, Kotlin 没有更优雅的解决方案吗?当然有。
as ?运算符尝试把值转换成指定的类型, 如果值不是合适的类型就返回 null,
一种常见的模式是把安全转换和 Elvis 运算符结合使用。例如,实现 equals 方法的时候这样的用法非常方便。
class Person(val firstName: String,val lastName: String){
override fun equals(o: Any?): Boolean{
val otherPerson = o as? Person ?: return false
return otherPerson.firstName == firstName && otherPerson.lastName == lastName
}
override fun hashCode(): Int = firstName.hashCode() * 37 + lastName.hashCode
}
使用这种模式,可以非常容易地检查实参是否是适当的类型,转换它,并在它 的类型不正确时返回 false,而且这些操作全部在同一个表达式中。当然,这种场 景下智能转换也会生效 : 当你检查过类型并拒绝了 null 值,编译器就确定了变量 otherPerson 值的类型是 Person 并让你能够相应地使用它。
非空断言是 Kotlin 提供给你的最简单直率的处理可空类型值的工具。它使用双感叹号表示,可以把任何值转换成非空类型。如果对 null 值做非空断言,则会抛出异常
如前面的代码
fun strLen(s: String?) = s.length
fun strLen(s: String?) = s!!.length
第一行代码会报Error,但是第二行就不会了。可以顺利编译通过。
如果第二行中的s为null会发生什么?kotlin没有其他选择,只会抛出空指针异常。
let 函数让处理可空表达式变得更容易。 和安全调用运算符一起,它允许你对表达式求值,检查求值结果是否为 null,并把结果保存为一个变量。 所有这些动作都在同一个简洁的表达式中。
fun sendEmailTo(email: String) {
println("Sending email to $email")
}
var email: String? = "yole@example.com"
email?.let { sendEmailTo(it) }
email = null
email?.let { sendEmailTo(it) }
如果email = null则下面的一行代码不会被调用
为可空类型定义扩展函数是一种更强大的处理 null 值的方式。可以允许接收 者为 null 的(扩展函数)调用,并在该函数中处理 null,而不是在确保变量不 为 null 之后再调用它的方法。只有扩展函数才能做到这一点,普通成员方法的调 用是通过对象实例来分发的,因此实例为 null 时(成员方法)永远不能被执行。
Kotlin 标准库中定义的 String 的两个扩展函数 isEmpty 和 isBlank 就 是这样的例子。第一个函数判断字符串是否是一个空的字符串 ””。第二个函数 则判断它是否是空的或者它只包含空白字符。通常用这些函数来检查字符串是有 价值的,以确保对它的操作是有意义的。你可能意识到了,像处理无意义的空字 符串和空白字符串这样处理 null 也很有用。事实上,你的确可以这样做:函数 isEmptyOrNull 和 isNullOrBlank 就可以由 String?类型的接收者调用。
fun verifyUserInput(input: String){
if(input.isNullOrBlank()){
println("please fill in the required fields")
}
}
函数 isNullOrBlank 显式地检查了 null ,这种情况下返回 true ,然后调 用 isBlank,它只能在非空 String 上调用:
fun String?.isNullOrBlank(): Boolean = this == null || this.isBlank()
以上,描述了kotlin关于可空,和空处理的几种方式。
参考:《实战kotlin》
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。