一、为空性(Nullability)
Kotlin类型系统的为空性(Nullability)可能帮助你避免NullPointerException错误,比如"An error has occurred: java.lang.NullPointerException"或者"Unfortunately, the application X has stopped",现代语言(包括kotlin在内)的解决方法是把这些问题由运行时错误(runtime errors )转变为编译时错误(compile-time errors)。
1.1 可空类型(Nullable types)
Kotlin显式支持nullable types, 这是Kotlin与Java类型系统的第一个、可能也是最重要的不同点。Kotlin中的nullable类型和non-null类型是不同的。
举例:
fun strLen(s: String) = s.length
如果调用strLen(null)就会报错。
>>> strLen(null)
ERROR: Null can not be a value of a non-null type String
注意:nullable类型和non-null类型的对象在运行期是一样的,一个nullable类型并不是对non-null类型的wrapper,所有的checks都是在编译期执行的,因此在kotlin中使用nullable类型是没有运行期开销(runtime overhead)的。
1.2 Safe call 操作符: “?.”
表达式s?.toUpperCase()等价于if (s != null) s.toUpperCase() else null.
多个Safe call操作符的链式调用:
class Address(
val streetAddress: String, val zipCode: Int,
val city: String, val country: String
)
class Company(val name: String, val address: Address?)
class Person(val name: String, val company: Company?)
fun Person.countryName(): String {
return company?.address?.country ?: "Unknown"
}
fun main(args: Array<String>) {
val person = Person("Dmitry", null)
println(person.countryName()) //null
}
1.3 Elvis操作符: “?:”
含义:为null提供一个默认值,它是Java中三元运算符的一个缩写。
举个例子:
fun strLenSafe(s: String?): Int = s?.length ?: 0
等价于Java的
int strLenSafe(String s) {
return s != null ? s.length : 0;
}
也可以在Evlis操作符也可以与抛出异常结合使用。
class Address(val streetAddress: String, val zipCode: Int,
val city: String, val country: String)
class Company(val name: String, val address: Address?)
class Person(val name: String, val company: Company?)
fun printShippingLabel(person: Person) {
val address = person.company?.address
?: throw IllegalArgumentException("No address")
with (address) {
println(streetAddress)
println("$zipCode $city, $country")
}
}
fun main(args: Array<String>) {
val jetbrains = Company("JetBrains", null)
val person = Person("Dmitry", jetbrains)
printShippingLabel(person)
}
输出:
Exception in thread "main" java.lang.IllegalArgumentException: No address
1.4 Safe casts操作符:“as?”
举例:
使用safe cast实现equals方法
class Person(val firstName:String, val lastName:String) {
override fun equals(other: Any?): Boolean {
val otherPerson = other as? Person ?: return false
return otherPerson.firstName == firstName &&
otherPerson.lastName == lastName
}
}
1.5 Not-null assertions:“!!”
使用非空断言其实是告诉编译器:
“I know the value isn’t null, and I’m ready for an exception if it turns out I’m wrong.”
二、类型参数的为空性
2.1 处理可为空类型的参数
class MyService {
fun performAction(): String = "foo"
}
fun <T> printHashCode(t: T) {
println("type: " + t + ", hashCode: " + t.hashCode())
}
fun main(args: Array<String>) {
val myService: MyService? = null
printHashCode(myService) //"T" is inferred as "Any?".
}
输出结果:
type: null, hashCode: 0
2.2 处理非空类型的参数
class MyService {
fun performAction(): String = "foo"
}
//“T” can’t be nullable.
fun <T : Any> printHashCode(t: T) {
println(t.hashCode())
}
fun main(args: Array<String>) {
val myService: MyService? = null
printHashCode(myService) //compile-error: Type mismatch: inferred type is MyService? but TypeVariable(T) was expected
}
Any和Any?: the root types
Any是所有类型的父类型,包括原始类型(primitive type)在内。
注意Any是一个非空类型(non-nullable type),也就意味着它不能持有null,如果需要的话,需使用Any?。
举例:
val answer: Any = 42 //42会被自动装箱(automatically boxed), 因为Any是一个引用类型.