序列性能优化 (Sequences)
Kotlin 的 Sequence 类似于 Java 8 的 Stream。它采用 惰性求值 (Lazy Evaluation) 策略,显著区别于 Iterable (List/Set) 的 及早求值 (Eager Evaluation)。
核心差异:流水线 vs 堆积木
Iterable (List)
每个操作符(map, filter)都会立即执行并创建完整的中间集合。
kotlin
// 假设 list 有 100 万个元素
list.map { it * 2 } // 步骤 1: 创建一个包含 100 万元素的中间 List
.filter { it > 10 } // 步骤 2: 遍历中间 List,再创建最终 List
.first() // 步骤 3: 取第一个缺点:内存开销大,无法处理无限数据流。
Sequence
所有操作符被构建成一个流水线。只有当终端操作符(如 toList, first)被调用时,数据才开始流动。
kotlin
list.asSequence()
.map { it * 2 } // 仅注册操作
.filter { it > 10 } // 仅注册操作
.first() // 开始拉取数据:处理第 1 个 -> map -> filter -> 满足 -> 停止!优点:几乎无中间内存开销,支持短路优化。
序列构建器:yield
sequence { ... } 构建器允许你通过挂起函数 yield 生成数据。这是一个受限的 协程 环境。
kotlin
val fibonacci = sequence {
var a = 0
var b = 1
// 无促生成无限序列,因为 sequence 是惰性的
// 不会造成死循环
while (true) {
yield(a) // 暂停执行,返回值给调用者,直到下一次请求
val temp = a + b
a = b
b = temp
}
}
// 取前 10 个
println(fibonacci.take(10).toList())性能基准 (Benchmark)
并不是说所有情况都应该用 Sequence。
| 数据量 | 操作链长度 | 推荐 | 原因 |
|---|---|---|---|
| 小 (< 100) | 任意 | Iterable | Sequence 自身的对象创建和状态机管理有微小开销,小数据量下得不偿失。 |
| 大 (> 1000) | 多步 (Map+Filter) | Sequence | 避免中间集合创建,显著降低 GC 压力。 |
| 无限/流式 | 任意 | Sequence | Iterable 根本无法处理无限流。 |
| 包含短路 | 任意 (take, first) | Sequence | 避免处理不必要的后续元素。 |
实战:IO 流处理
利用 Sequence 逐行处理大文件,避免 OOM。
kotlin
// useLines 内部就是由 Sequence 实现的
File("gigantic.log").useLines { lines ->
lines
.filter { it.contains("ERROR") } // 只处理错误行
.map { it.extractErrorCode() }
.distinct()
.forEach { report(it) }
}约束:单次迭代
大部分 Sequence(尤其是基于 Iterator 或 Generator 的)只能被消费一次。如果需要多次遍历,请先 toList() 转为集合。