跳到主要内容

Kotlin Lambda 表达式

Lambda 表达式是 Kotlin 函数式编程的核心。本章将详细介绍 Lambda 的语法、高阶函数和内联优化。

Lambda 基础

什么是 Lambda?

Lambda 是"匿名函数",即没有名称的函数:

// 普通函数
fun sum(a: Int, b: Int): Int {
return a + b
}

// Lambda 表达式
val sum = { a: Int, b: Int -> a + b }

Lambda 语法

{ 参数列表 -> 函数体 }

// 完整示例
val add: (Int, Int) -> Int = { a, b -> a + b }

// 调用
println(add(1, 2)) // 3

类型推断

// 完整类型
val add: (Int, Int) -> Int = { a, b -> a + b }

// 省略类型(可推断)
val add2 = { a: Int, b: Int -> a + b }

// 错误推断
// val add3 = { a, b -> a + b } // 编译错误!无法推断参数类型

Lambda 作为参数

高阶函数

// 接受 Lambda 作为参数
fun calculate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
return operation(a, b)
}

fun main() {
// 传入 Lambda
val result = calculate(10, 5) { a, b -> a + b }
println(result) // 15

// 多行 Lambda
val result2 = calculate(10, 5) { a, b ->
val sum = a + b
sum * 2
}
println(result2) // 30
}

it - 隐式参数名

当 Lambda 只有一个参数时,可以使用 it

fun main() {
val list = listOf(1, 2, 3, 4, 5)

// 完整写法
list.filter { x -> x > 3 }

// 使用 it
list.filter { it > 3 }

// map 使用 it
list.map { it * 2 } // [2, 4, 6, 8, 10]

// forEach 使用 it
list.forEach { println(it) }
}

it 的使用场景

fun main() {
// 适用于单参数情况
val numbers = listOf(1, 2, 3, 4, 5)

// filter
println(numbers.filter { it > 2 }) // [3, 4, 5]

// map
println(numbers.map { it * 10 }) // [10, 20, 30, 40, 50]

// any / all / none
println(numbers.any { it > 3 }) // true
println(numbers.all { it > 0 }) // true
println(numbers.none { it < 0 }) // true

// find / findLast
println(numbers.find { it > 2 }) // 3
println(numbers.findLast { it > 2 }) // 5
}

Lambda 返回值

最后一行作为返回值

fun main() {
// 最后一行作为返回值
val result = if (true) {
val a = 10
a + 5 // 返回 15
} else {
0
}
println(result) // 15

// Lambda 最后一行
val lambdaResult = { x: Int ->
val doubled = x * 2
val plusOne = doubled + 1
plusOne // 返回 doubled + 1
}(5)
println(lambdaResult) // 11
}

常见高阶函数

map - 转换

fun main() {
val list = listOf(1, 2, 3, 4, 5)

// 每个元素 * 2
println(list.map { it * 2 }) // [2, 4, 6, 8, 10]

// 转换类型
println(list.map { "Number: $it" }) // [Number: 1, Number: 2, ...]

// 带索引
println(list.mapIndexed { index, value -> "$index: $value" })
// [0: 1, 1: 2, 2: 3, 3: 4, 4: 5]
}

filter - 过滤

fun main() {
val list = listOf(1, 2, 3, 4, 5)

// 过滤奇数
println(list.filter { it % 2 == 1 }) // [1, 3, 5]

// 过滤大于 2
println(list.filter { it > 2 }) // [3, 4, 5]

// 带索引过滤
println(list.filterIndexed { index, value -> index % 2 == 0 })
// [1, 3, 5]
}

reduce / fold - 聚合

fun main() {
val list = listOf(1, 2, 3, 4, 5)

// reduce - 无初始值
println(list.reduce { acc, i -> acc + i }) // 15

// fold - 有初始值
println(list.fold(10) { acc, i -> acc + i }) // 25

// 其他聚合
println(list.sum()) // 15
println(list.maxOrNull()) // 5
println(list.minOrNull()) // 1
}

flatMap - 扁平化

fun main() {
val words = listOf("hello", "world")

// 每个单词拆分成字符
println(words.flatMap { it.toList() })
// [h, e, l, l, o, w, o, r, l, d]

// 生成多个元素
println(listOf(1, 2, 3).flatMap { listOf(it, it * 10) })
// [1, 10, 2, 20, 3, 30]
}

sortedBy / sortedWith - 排序

fun main() {
data class Person(val name: String, val age: Int)

val people = listOf(
Person("Tom", 25),
Person("Jerry", 20),
Person("Spike", 30)
)

// 按年龄排序
println(people.sortedBy { it.age })
// [Jerry(20), Tom(25), Spike(30)]

// 按年龄降序
println(people.sortedByDescending { it.age })
// [Spike(30), Tom(25), Jerry(20)]

// 多条件排序
println(people.sortedWith(compareBy({ it.age }, { it.name })))
}

函数引用

:: 操作符

fun main() {
val numbers = listOf(1, 2, 3, 4, 5)

// 方法引用
println(numbers.map { it.toString() })
println(numbers.map(Int::toString))

// 函数引用
fun isEven(n: Int) = n % 2 == 0
println(numbers.filter(::isEven)) // [2, 4]

// 类方法引用
val strings = listOf("abc", "a", "abcd")
println(strings.sortedBy(String::length))
// [a, abc, abcd]
}

闭包

访问外部变量

fun main() {
// 访问外部变量
var factor = 2

val multiply: (Int) -> Int = { x -> x * factor }
println(multiply(5)) // 10

// 修改外部变量
factor = 3
println(multiply(5)) // 15

// 在 Lambda 中修改可变变量
var sum = 0
listOf(1, 2, 3, 4, 5).forEach { sum += it }
println(sum) // 15
}

内联函数

inline 关键字

// 内联函数 - 减少函数调用开销
inline fun measureTime(block: () -> Unit): Long {
val start = System.currentTimeMillis()
block()
return System.currentTimeMillis() - start
}

fun main() {
val time = measureTime {
Thread.sleep(100)
}
println("Time: $time ms")
}

noinline 和 crossinline

// noinline - 禁止特定参数内联
inline fun example1(inlined: () -> Unit, noinline notInlined: () -> Unit) {
inlined()
// notInlined() // 可以调用,但不能作为返回值
}

// crossinline - 允许非局部返回
inline fun example2(crossinline block: () -> Unit) {
Runnable { block() }.run()
}

Lambda 与异常

fun main() {
// Lambda 中的异常需要显式处理
val numbers = listOf("1", "2", "abc", "4")

// try-catch 在 Lambda 内部
val results = numbers.map { str ->
try {
str.toInt()
} catch (e: NumberFormatException) {
0
}
}
println(results) // [1, 2, 0, 4]

// runCatching - Kotlin 提供的异常处理
val results2 = numbers.mapNotNull { str ->
str.toIntOrNull()
}
println(results2) // [1, 2, 4]
}

常用模式

run / let / also / apply

fun main() {
// let - 在对象上执行操作,返回结果
val result = "Hello".let { it.uppercase() }
println(result) // HELLO

// run - 类似 let,但使用 this
val result2 = "Hello".run { uppercase() }
println(result2) // HELLO

// also - 执行额外操作,返回原对象
val list = mutableListOf(1, 2, 3).also {
println("Before: $it")
}.apply {
add(4)
add(5)
}
println("After: $list")

// with - 使用参数对象的函数
val person = Person("Tom", 25)
val info = with(person) {
"Name: $name, Age: $age"
}
println(info)
}

takeIf / takeUnless

fun main() {
// takeIf - 满足条件返回对象,否则返回 null
val num = 10
val result = num.takeIf { it > 5 }
println(result) // 10

val result2 = num.takeIf { it < 5 }
println(result2) // null

// takeUnless - 不满足条件返回对象,否则返回 null
val result3 = num.takeUnless { it > 5 }
println(result3) // null

val result4 = num.takeUnless { it < 5 }
println(result4) // 10
}

小结

本章我们学习了:

  1. Lambda 基础:语法、类型推断
  2. it 关键字:单参数隐式名称
  3. 高阶函数:map, filter, reduce, fold 等
  4. 函数引用:: 操作符
  5. 闭包:访问和修改外部变量
  6. 内联函数:inline, noinline, crossinline
  7. 常用函数:run, let, also, apply, takeIf

练习

  1. 使用 Lambda 表达式过滤列表中的偶数
  2. 使用 map 转换元素,使用 reduce 计算总和
  3. 使用函数引用简化代码
  4. 理解 run/let/also/apply 的区别
  5. 使用 takeIf 实现条件返回