Kotlin
基础(四)类型系统
可空性
可空性是Kotlin
类型系统中帮助避免NullPointerException
错误的特性。
可空使用?
表示:
Type? = Type or null
安全调用运算符:?.
s?.toUpperCase()
//等价于
if(s!=null) s.toUpperCase() else null
即:调用一个非空值的方法,如果该值不为空,正常执行; 为空则值为null,调用不执行
foo?.bar()
//等价于
if (foo != null) foo.bar() else null
Elvis运算符:?:
fun foo(s: String?) {
val t: String = s ?: ""
}
Elvis
运算符接受两个参数,第一个不为null
则值为第一个运算数,若为null
,则值为第二个运算数。
foo ?: bar
//等价于
if (foo != null) foo else bar
安全转换符:as?
foo as? Type
//等价于
if (foo is Type) {
foo as Type
} else {
null
}
安全转换和Elvis
运算符结合使用:
class Person(val name: String) {
override fun equals(other: Any?): Boolean {
val op = other as? Person ?: return false
return op.name.equals(name)
}
override fun hashCode(): Int {
return name.hashCode()
}
}
非空断言
非空断言是Kotlin
提供最简单直接的可空类型处理工具,如果值为null,直接抛出NullPoniterException
. 异常抛出点在断言处而非值调用处。
foo!!
//等价于
if (foo != null) {
foo
} else {
throw NullPointerException()
}
let
函数
let
函数就是把一个调用它的对象变成lambda
表达式的参数,如果结合安全调用语法,能有效的把调用let
函数的可空对象转变成非空类型。
foo?.let{
/*...*/
}
//等价于
if (foo != null) {
//调用lambda表达式
} else {
//不执行
}
延迟初始化的属性
Kotlin
通常要求在构造函数中初始化所有的属性,如果某个属性不为非空类型就必须提供非空初始化值,否则,需要使用可空类型。但如果使用可空类型,每次调用都要做null检测或者非空断言。
lateinit var hobby :String
在初始化前访问一个 lateinit
属性会抛出一个特定异常,该异常明确标识该属性被访问及它没有初始化的事实。
要检测一个 lateinit var
是否已经初始化过,请在该属性的引用上使用 .isInitialized
:
if (foo::bar.isInitialized) {
println(foo.bar)
}
类型参数的可空性
kotlin
中所有泛型类和泛型函数的类型参数默认都是可空的。
fun <T> printHashCode(t:T){
println(t?.hashCode())
}
可空类型
Java
把基本数据类型和引用类型做区分,基本数据类型直接存储值,而引用类型变量存储对象的内存地址;Kotlin
并不区分数据基本类型和包装类型,永远使用同一个类型。但为了保证运行效率,在大多数情况下,对于变量,属性,参数和返回值类型,Koltin
的Int
等数据类型会被编译成Java
基本数据类型int
,而泛型类,如集合,用作泛型类型参数的基本数据类型会被编译成对应的Java
包装类型。
Kotlin
中的可空类型不能使用java
的基本数据类型表示,因为null
只能被存储在java
的引用类型的变量中,意味着任何时候只要使用了可空类型的基本数据类型都会被编译成对应的包装类型。
Any
,Any?
根类型
Any
类型是Kotlin
所有非空类型的超类型(非空类型的根),包含Int
这样的基本数据类型。
//Any是引用类型,值42会被装箱
val answer: Any= 42
Unit
类型:Kotlin
的void
Kotlin
中的Unit
类型和Java
中的void
功能一样。当函数没有任何返回结果,用作函数的返回类型:
fun f() :Unit{
/*...*/
}
Unit
是一个完备的类型,可以作为类型参数,而void
则不行,只存在一个值是Unit
类型,这个值也可作Unit
,并在函数中被隐式返回:
interface Processor<T> {
fun process(): T
}
class NoResultProcessor : Processor<Unit> {
override fun process() {
//...
}
}
Nothing
类型:函数不返回
知道函数永远不会正常终止,没有返回,用Nothing
类型:
fun fail(message: String): Nothing {
throw IllegalArgumentException(message)
}
Nothing
类型没有任何值,只有被当作函数的返回值使用,或者被当作泛型函数的返回值的类型参数使用才有意义。
同样,Nothing
可以结合Elvis
运算符使用:
val address= company.address ?: fail("No address")