文章目录

Kotlin 函数式编程:lambda 表达式与高阶函数

发布于 2026-04-03 17:12:24 · 浏览 3 次 · 评论 0 条

Kotlin 函数式编程:lambda 表达式与高阶函数

Kotlin 支持函数式编程范式,其中 lambda 表达式高阶函数 是两大核心特性。它们能让你写出更简洁、更具表达力的代码,尤其在处理集合操作、事件回调或数据转换时非常高效。以下内容将手把手教你掌握这两个关键概念,并通过实际代码示例展示如何正确使用。


理解 lambda 表达式

lambda 表达式是一种匿名函数,通常用于简短地表示一个函数逻辑,无需显式声明函数名。

定义 lambda 表达式 的基本语法如下:

{ 参数 -> 函数体 }

例如,一个接收两个整数并返回它们和的 lambda 表达式写作:

{ a: Int, b: Int -> a + b }

你也可以将其赋值给变量以便复用:

val sum = { a: Int, b: Int -> a + b }
println(sum(3, 4)) // 输出 7

当 lambda 表达式作为函数的最后一个参数时,Kotlin 允许你把它写在括号外面,这是常见的调用风格:

listOf(1, 2, 3).forEach { println(it) }

这里 it 是 lambda 表达式只有一个参数时的默认名称。


掌握高阶函数

高阶函数是指接受函数作为参数返回函数的函数。Kotlin 标准库中大量使用了高阶函数,比如 mapfilterfold 等。

创建自己的高阶函数

定义一个高阶函数,让它接收一个函数类型的参数:

fun operateOnNumbers(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
    return operation(a, b)
}

调用它时传入一个 lambda 表达式:

val result = operateOnNumbers(5, 3) { x, y -> x * y }
println(result) // 输出 15

注意:operation 的类型是 (Int, Int) -> Int,表示一个接收两个 Int 并返回 Int 的函数。

使用函数引用简化代码

除了 lambda,你还可以传递已有函数的引用。假设有如下命名函数:

fun multiply(x: Int, y: Int): Int = x * y

你可以这样调用高阶函数:

val result = operateOnNumbers(5, 3, ::multiply)

::multiply 是对 multiply 函数的引用,其类型与 (Int, Int) -> Int 匹配。


实战:集合操作中的函数式编程

Kotlin 的集合类(如 ListSet)提供了丰富的高阶函数,配合 lambda 表达式可实现强大的数据处理能力。

过滤与映射

过滤出偶数并平方

val numbers = listOf(1, 2, 3, 4, 5, 6)
val squaredEvens = numbers
    .filter { it % 2 == 0 }   // 保留偶数
    .map { it * it }          // 每个元素平方
println(squaredEvens) // 输出 [4, 16, 36]

折叠计算(累加、拼接等)

计算列表所有元素之和

val total = numbers.fold(0) { acc, value -> acc + value }
println(total) // 输出 21

fold 的第一个参数是初始值(这里是 0),lambda 中 acc 是累积值,value 是当前元素。

你也可以用更简洁的写法:

val total = numbers.sum()

fold 更通用,适用于自定义累积逻辑,比如拼接字符串:

val words = listOf("Kotlin", "is", "awesome")
val sentence = words.fold("") { acc, word -> 
    if (acc.isEmpty()) word else "$acc $word" 
}
println(sentence) // 输出 "Kotlin is awesome"

避免常见陷阱

虽然 lambda 和高阶函数很强大,但使用不当会导致性能或可读性问题。

注意闭包中的变量捕获

lambda 表达式可以访问外部作用域的变量,这称为“闭包”:

var factor = 2
val multiplier = { x: Int -> x * factor }
println(multiplier(5)) // 输出 10
factor = 3
println(multiplier(5)) // 输出 15

修改外部变量会影响 lambda 的行为。如果不需要这种动态性,应避免在 lambda 中引用可变变量。

避免过度嵌套

多层 lambda 嵌套会降低可读性:

// 不推荐
data.filter { it.isActive }
    .map { user ->
        user.orders.filter { order -> order.total > 100 }
            .map { order -> order.id }
    }

拆分为多个步骤或提取为命名函数更清晰:

val validOrders = data
    .filter { it.isActive }
    .flatMap { user ->
        user.orders.filter { it.total > 100 }
    }
    .map { it.id }

使用 flatMap 可以自动展平嵌套列表,避免 List<List<T>>


性能考量:内联函数

高阶函数在运行时会创建匿名类实例(在 JVM 上),可能带来轻微性能开销。对于频繁调用的小型高阶函数,可用 inline 关键字优化:

inline fun <T> myFilter(list: List<T>, predicate: (T) -> Boolean): List<T> {
    val result = mutableListOf<T>()
    for (item in list) {
        if (predicate(item)) {
            result.add(item)
        }
    }
    return result
}

添加 inline,编译器会在调用处直接插入 lambda 的代码,避免对象分配。

但注意:不要滥用 inline。如果函数体很大或 lambda 被存储(如赋值给变量),内联反而会增大字节码体积。


实用模式总结

下表列出常用高阶函数及其典型用途:

函数名 作用 示例
map 转换每个元素 list.map { it.toString() }
filter 筛选满足条件的元素 list.filter { it > 0 }
find 查找第一个匹配元素 list.find { it.name == "Alice" }
any/all 判断是否存在/全部满足 list.any { it.isExpired }
fold 累积计算 list.fold(0) { acc, i -> acc + i }
let 安全调用并转换 obj?.let { process(it) }
also 用于副作用(如日志) obj.also { println("Got: $it") }

这些函数组合使用,几乎可以替代传统 for 循环,使代码更声明式、更易测试。


将业务逻辑拆解为小的高阶函数组合,是写出简洁 Kotlin 代码的关键。从今天开始,在处理集合或需要回调的地方,优先考虑 lambda 表达式与标准库高阶函数。

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文