本章节主要对第四章描述的函数类型进行更进一步的描述,讲解Kotlin高阶函数、内联函数等细节。

高阶函数
参数类型包含函数类型或返回值类型为函数类型的函数为高阶函数
1 2 3 4 5 6 7 8 9
| fun needsFunction(block: () -> Unit) {
}
fun returnsFunction(): () -> Long { return { System.currentTimeMillis() } }
|
以intArray
扩展函数示例
1 2 3 4 5 6 7 8
| inline fun IntArray.forEach(action: (Int) -> Unit): Unit { for (element in this) action(element) }
inline fun <R> IntArray.map(transform: (Int) -> R): List<R> { return mapTo(ArrayList<R>(size), transform) }
|
高阶函数的调用
1 2 3
| intArray.forEach{ println("Hello $it") }
|
内联函数(减少函数调用开销)
上面的IntArray
的示例,使用了inline
关键字,这是内联函数的定义,内联函数会在编译器将函数定义搬运到调用处,而不是调用此函数

高阶函数内联
高阶函数与内联更配
- 函数本身被内联到调用处
- 函数的函数参数被内联到调用处
1 2 3
| val start = System.currentTimeMillis() println("Hello") println(System.currentTimeMillis() - start)
|
内联高阶函数的返回值(return@高阶函数名称)
1 2 3 4 5
| val ints = intArrayOf(1, 2, 3, 4) ints.forEach{ if(it == 3) return@forEach println("Hello $it") }
|
代码执行逻辑等同于
1 2 3 4 5
| val ints = intArrayOf(1, 2, 3, 4) for(element in ints) { if(it == 3) continue println("Hello $it") }
|
non-local return
1 2 3 4 5 6 7 8 9
| inline fun nonLocalReturn(block: () -> Unit) { block() }
fun main() { nonLocalReturn { return } }
|
如果在高阶函数内部,直接跳出到main函数,显然是不对的,例如
1 2 3 4 5 6 7
| inline fun Runnable(block: () -> Unit): Runnable { return object: Runnable { override fun run() { block() } } }
|
crossinline:禁止non-local return
可以使用crossinline
禁止non-local return
1 2 3 4 5 6 7
| inline fun Runnable(crossinline block: () -> Unit): Runnable { return object: Runnable { override fun run() { block() } } }
|
noinline:禁止函数参数被内联
1 2 3 4 5 6 7
| inline fun Runnable(noinline block: () -> Unit): Runnable { return object: Runnable { override fun run() { block() } } }
|
内联属性
没有backing-field的属性的getter/setter可以被内联
1 2 3 4 5 6
| var pocket: Double = 0.0 var money: Double inline get() = pocket inline set(value) { pocket = value }
|
内联函数的限制
public/protected
的内联方法只能访问对应类的public
成员- 内联函数的内联函数参数不能被存储(赋值给变量)
- 内联函数的内联函数参数只能传递给其他内联函数参数
几个有用的高阶函数
函数名 | 介绍 | 推荐指数 |
---|
let | val r = X.let { x -> R } | ⭐⭐⭐ |
run | val r = X.run { this: X -> R } | ⭐ |
also | val x = X.also { x -> Unit } | ⭐⭐⭐ |
apply | val r = X.apply { this: X -> Unit } | ⭐ |
use | val r = Closeable.use{ c -> R } | ⭐⭐⭐ |
这里的推荐指数,是教程作者根据是否绑定receiver做判断的,实际上这几个函数是有各自的意义的,参考下图,明确每个函数的使用场景

集合变换与序列
filter 变换
Java
1
| list.stream().filter(e -> e % 2 == 0);
|
Kotlin
1
| list.filter{ it % 2 == 0 }
|
转换为懒序列,即只有执行到该元素时,才会执行filter{ xxx }
的xxx函数
Java
1
| list.stream().filter(e -> e % 2 == 0);
|
Kotlin
1 2
| list.asSequence() .filter{ it % 2 == 0 }
|
map变换
Java
1
| list.stream().map(e -> e * 2 + 1);
|
Kotlin
flatMap变换
实际上是map与flatten(展平)结合起来

集合的聚合操作
函数名 | 说明 |
---|
sum | 所有元素求和 |
reduce | 将元素一次按规则聚合,结果与元素类型一致 |
fold | 给定初始化值,将元素按规则聚合,结果与初始化值类型一致 |
SAM
仅具有一种抽象方法的接口被称为功能接口,并且也被称为单一抽象方法接口(SAM接口)。一个抽象方法意味着允许使用默认方法或默认实现的抽象方法。
Java的SAM转换
一个参数类型为只有一个方法的接口的方法调用时可用Lambda表达式做转换作为参数
1 2 3 4 5 6 7 8
| () -> System.out.println("run in executor.")
new Runnable() { @Override public void run() { System.out.println("run in executor."); } }
|
Kotlin的SAM转换
1 2 3 4 5 6 7
| executor.submit { println("run in executor.") }
executor.submit(object: Runnable { override fun run() { println("run in executor.") } })
|
DSL领域特定语言

建议查看示例:AdvancedFunctions-Htmls.kt