在Kotlin中,Sequence是惰性序列,允许有效处理大规模甚至潜在无限的数据集。对Sequence的操作(例如,map、filter)不会立即执行;相反,它构建一个操作链,计算仅在需要时(即进行终止操作时,例如toList)发生。
为什么这很重要:
代码示例:
val numbers = generateSequence(1) { it + 1 } .filter { it % 2 == 0 } .map { it * it } .take(5) .toList() println(numbers) // [4, 16, 36, 64, 100]
在这个例子中,尽管序列是潜在无穷的,只有前5个元素会被实际计算。
何时使用Sequence:
能否保证Kotlin中普通集合的操作符如
map和filter也是惰性的?为什么?
**答案:**不,Kotlin中的标准集合操作(List.map、List.filter等)是_严格贪婪的_。每个操作都会创建一个中间集合,并立即处理所有元素。惰性仅在使用Sequence时得到支持。
示例:
val data = listOf(1,2,3,4) val mapped = data.map { println("Mapping $it"); it * 2 } // 立即打印所有值
故事
在处理大量CSV文件(每个文件高达一GB)的项目中,集合最初完全加载到List中,然后应用链式map/filter。应用程序因内存溢出而崩溃——问题通过将List替换为Sequence得以解决,后者的map/filter不会创建巨大的中间列表。
故事
为从多个数据库中聚合报告而构建的后端服务最初将搜索结果累积在List中,然后进行过滤:请求变得缓慢,GC延迟明显。用生成器+Sequence的替换使数据能够即时汇总,显著降低了延迟。
故事
从Java迁移过来的项目在处理大量数据流时使用了Kotlin的标准扩展(map、filter),而没有转向Sequence,误认为代码是惰性的,类似于Java 8的流。此错误导致严重的内存泄漏和生产环境中的突然崩溃。