高阶函数与 Lambda
本教程共 100 篇 · 第 17 篇 · 更新于 2026-07-28 · 约 8 分钟阅读
17. 高阶函数与 Lambda
本节目标:理解函数类型、掌握 Lambda 写法、知道 inline 函数为什么能优化性能、熟练用集合操作符处理数据。
什么是高阶函数
高阶函数就是接收函数作为参数、或者返回函数的函数。Kotlin 里函数是「一等公民」,能像变量一样传来传去。
最典型的例子是集合操作符:
val nums = listOf(1, 2, 3, 4)
nums.filter { it > 2 } // { it > 2 } 就是个 Lambda
nums.map { it * 10 }
nums.forEach { println(it) }
filter 接收一个「判断函数」作为参数,这个函数对每个元素求值返回 Boolean。把「做什么」作为参数传给「怎么遍历」,就是高阶函数的精髓。
函数类型
Kotlin 用 (参数类型) -> 返回类型 表示函数类型:
val add: (Int, Int) -> Int = { a, b -> a + b }
val isEven: (Int) -> Boolean = { it % 2 == 0 }
val greet: (String) -> Unit = { name -> println("Hello, $name") }
println(add(1, 2)) // 3
println(isEven(4)) // true
greet("Android") // Hello, Android
(Int, Int) -> Int表示接收两个 Int 返回 Int 的函数。- 无参数写成
() -> Int。 - 无返回值写成
(Int) -> Unit。
类型别名
复杂函数类型用 typealias 起个短名:
typealias ClickHandler = (View) -> Unit
fun setClickListener(handler: ClickHandler) { /* ... */ }
Lambda 表达式
Lambda 是匿名函数的简写:{ 参数 -> 函数体 }。
val sum = { a: Int, b: Int -> a + b }
println(sum(1, 2)) // 3
it 隐式参数
Lambda 只有一个参数时,可以省略参数声明,用 it 引用:
val square: (Int) -> Int = { it * it }
末尾 Lambda 约定
函数最后一个参数是函数类型时,Lambda 可以提到括号外:
// 标准写法
list.fold(0, { acc, n -> acc + n })
// 约定写法,更清晰
list.fold(0) { acc, n -> acc + n }
如果函数只有 Lambda 一个参数,括号都能省:
list.forEach { println(it) }
Tip
- 这个约定让 Kotlin 写 DSL(如 Compose)特别自然。
Column { Text("hi") }这种写法就是末尾 Lambda。
函数作为参数
fun performOperation(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
return operation(a, b)
}
val result = performOperation(3, 4) { x, y -> x * y } // 12
val sum = performOperation(3, 4) { x, y -> x + y } // 7
策略模式不用定义接口了,直接传函数。
函数作为返回值
fun multiplier(factor: Int): (Int) -> Int {
return { n -> n * factor } // 捕获 factor
}
val double = multiplier(2)
val triple = multiplier(3)
println(double(5)) // 10
println(triple(5)) // 15
返回的 Lambda 捕获了外层的 factor,这种「闭包」是函数式编程的核心特性。
inline 内联函数
高阶函数每次调用会创建 Lambda 对象,有性能开销。inline 关键字让编译器把函数体直接展开到调用处,消除对象创建。
inline fun repeat(times: Int, action: (Int) -> Unit) {
for (i in 0 until times) action(i)
}
repeat(3) { println("第 $it 次") }
标准库的 let、run、apply、forEach、filter、map 都是 inline 的,所以用这些操作符不会增加额外对象开销。
Note
- 自定义高阶函数如果在性能敏感路径(循环、列表处理),加
inline。但inline会让编译产物变大,不要滥用。
noinline 与 crossinline
inline 函数里某些函数参数不想内联用 noinline;Lambda 里不能 return(non-local return)时用 crossinline。这两个进阶场景遇到再查,日常很少手写。
集合操作符进阶
第 15 章介绍过基本操作符,这里补充几个组合用法。
map / filter / flatMap
data class User(val name: String, val emails: List<String>)
val users = listOf(
User("张三", listOf("a@x.com", "b@x.com")),
User("李四", listOf("c@x.com"))
)
// 所有邮箱
val allEmails = users.flatMap { it.emails }
// [a@x.com, b@x.com, c@x.com]
// 邮箱数 >= 2 的用户
val multiEmail = users.filter { it.emails.size >= 2 }
// 用户名转大写
val names = users.map { it.name.uppercase() }
flatMap 把「列表的列表」拍平成单层列表。
fold / reduce
val sum = listOf(1, 2, 3, 4).fold(0) { acc, n -> acc + n } // 10
val product = listOf(1, 2, 3, 4).fold(1) { acc, n -> acc * n } // 24
val sum2 = listOf(1, 2, 3, 4).reduce { acc, n -> acc + n } // 10,无初始值
fold 有初始值,reduce 用第一个元素当初始值。
groupBy / associate
val users = listOf(
User("张三", 18, "北京"),
User("李四", 20, "上海"),
User("王五", 18, "北京")
)
// 按城市分组
val byCity = users.groupBy { it.city }
// {北京=[张三, 王五], 上海=[李四]}
// 按年龄分组,只取名字
val namesByAge = users.groupBy({ it.age }, { it.name })
// {18=[张三, 王五], 20=[李四]}
partition
按条件拆成两个列表:
val (minors, adults) = users.partition { it.age < 18 }
zip
两个列表按位置配对:
val names = listOf("张三", "李四")
val ages = listOf(18, 20)
val pairs = names zip ages // [(张三, 18), (李四, 20)]
val map = names.zip(ages).toMap() // {张三=18, 李四=20}
Android 实战
回调用 Lambda 替代接口
Java 风格的回调接口:
// Java 风格
interface OnDataLoaded {
fun onSuccess(data: List<Item>)
fun onError(error: Throwable)
}
fun loadData(callback: OnDataLoaded) { /* ... */ }
Kotlin 风格,直接用函数类型:
fun loadData(
onSuccess: (List<Item>) -> Unit,
onError: (Throwable) -> Unit
) { /* ... */ }
loadData(
onSuccess = { items -> showData(items) },
onError = { e -> showError(e.message ?: "未知错误") }
)
Compose 里到处是高阶函数
@Composable
fun UserList(users: List<User>, onUserClick: (User) -> Unit) {
LazyColumn {
items(users) { user ->
UserRow(user, onClick = { onUserClick(user) })
}
}
}
// 调用
UserList(users = userList) { user ->
// 点击处理,Lambda 提到括号外
navigateToDetail(user.id)
}
自定义 inline 工具
inline fun measureTime(block: () -> Unit): Long {
val start = System.currentTimeMillis()
block()
return System.currentTimeMillis() - start
}
val cost = measureTime {
// 耗时操作
doHeavyWork()
}
println("耗时 $cost ms")
小结
高阶函数接收或返回函数。函数类型用 (A) -> B 表示。Lambda 是 { 参数 -> 体 },单参数用 it,末尾 Lambda 可提括号外。inline 内联消除对象开销。集合操作符(map/filter/flatMap/fold/groupBy/zip)是数据处理利器。Android 里用 Lambda 替代回调接口,Compose 全靠高阶函数构建。下一节学协程基础。