Kotlin拾遗
return
关键字
从封闭函数中返回
1 | fun lookForAlice(people: List<Person>) { |
用标签返回
1 | people.forEach { |
函数名作为标签返回
1 | people.forEach { |
匿名函数局部返回
1 | people.forEach(fun(person) { |
面向对象
所有类默认为final
,需要显式声明open
以便继承。
主/次构造函数
类可以有一个主构造函数和多个次构造函数。
1 | class User(name: String) { // 此处实际上省略了constructor关键字 |
扩展函数
扩展函数不可以重写。
1 | fun Int.isEven() = this % 2 == 0 |
伴生对象
可以为伴生对象命名。
1 | companion object Loader { ... } |
为匿名伴生对象定义扩展函数时,需要使用默认名Companion
。
1 | fun ClsName.Companion.getSomething(): Type { ... } |
枚举类
软关键字
如此处的enum
,在class
前才起作用,其他处可以作为名称使用。
1 | enum class Color(rgb: Int) { |
下例获取枚举类常量的个数。
1 | val n = enumValues<EnumClsName>().size |
enumValues<T>()
返回一个Array<T>
,使可以通过泛型数组的形式访问枚举类的常量。
数据类
自动创建属性,它使用圆括号,且一般没有方法。
1 | data class User(var id: Int, var name: String) |
自定义运算符
等式校验
Kotlin和JAVA不同,a==b
相当于a?.equals(b)?:(b == null)
,而引用比较使用a===b
。
1 | override fun equals(obj: Any?): Boolean { |
equals()
在Any
中就有定义,意味着所有对象都支持等式校验。
!=
也会转换为equals()
的调用。
排序校验
要实现Comparable
接口,相关的运算符有>
、<
、>=
和<=
。
1 | class Person(...): Comparable<Person> { |
其他
1 | operator fun plus(other: Cls): Cls { ... } |
函数
高阶函数
函数的参数或返回值类型也为函数。
1 | fun String.filter(predicate: (Char) -> Boolean): String { |
闭包
当函数最末参数为lambda表达式,可写于括号外。
例如,Thread
的完全写法如下。
1 | Thread(object : Runnable { |
SAM(Single Abstract Method)
单抽象方法。
满足SAM,可简化为如下。
1 | Thread({ ... }) |
使用闭包还可简化为如下。
1 | Thread { ... } |
形如
Thread { ... }
的结构中,{}
就是一个闭包。
函数引用
1 | val fRef = ::f |
可以
fRef(params)
,其本质是fRef.invoke(params)
。
返回值可空的函数类型
1 | var canReturnNull: (Int, Int) -> Int? = { null } |
函数类型的可空变量
1 | var funOrNull: ((Int, Int) -> Int)? = null |
空安全
?.
空安全调用运算符
foo?.bar()
:
- 当
foo!=null
时,得到foo.bar()
; - 当
foo==null
时,得到null
。
?:
空值合并运算符
又称Elvis运算符。顺时针旋转90°,看起来像猫王Elvis一样。
foo?:bar()
:
- 当
foo!=null
时,得到foo
; - 当
foo==null
时,得到bar
。
as?
安全转换
foo as? Type
:
- 当
foo is Type
时,得到foo as Type
; - 当
foo !is Type
时,得到null
。
?:
和as?
可结合使用:b as? A ?: Type
。
!!
非空断言
一旦使用
!!
,空安全优势便不得体现。
foo!!
:
- 当
foo!=null
时,得到foo
; - 当
foo==null
时,得到NullPointerException
。
泛型
擦除
ERROR:
Cannot check for instance of erased type: T
.
1 | fun<T> isA(value: Any) = value is T // ERROR! |
实化
1 | inline fun<reified T> isA(value: Any) = value is T |
通配
1 | if(value is List<*>) { ... } |
上界约束
1 | fun<T: Number> oneHalf(value: T): Double { |
多重约束
1 | fun<T> ensureTrailingPeriod(seq: T) |
非空约束
1 | class Processor<T: Any> { ... } |
默认的
<T>
使T
的类型可空。
协变
1 | interface List<out T> { fun getSomething(index: Int): T } |
逆变
1 | interface Compare<in T> { fun compare(first: T, second: T): Int } |
多线程
协程(Coroutine)
一套线程API,即更方便的线程框架。
下例的调度器(Dispatchers)可将协程限制于特性线程执行,或将它分配至一个线程池,或让它不受限制地运行。
1 | launch(Dispatchers.Main) { // 在UI线程开始 |
非阻塞式挂起
非阻塞
协程的写法看似阻塞,但实际不然,故加以强调。
挂起
稍后会自动切回的线程切换。
自定义挂起函数而未调用挂起函数(如下例的withContext()
)将提示suspend
为冗余。
关键字
suspend
仅是标识提醒的作用,与挂起的实现无关。
1 | suspend fun getInfo() = withContext(Dispatchers.IO) { |