Kotlin 序列 #

一、序列概述 #

Sequence(序列)是 Kotlin 中的一种惰性集合,只有在需要结果时才会执行操作。

1.1 与 List 的区别 #

kotlin
// List:立即执行
val list = listOf(1, 2, 3, 4, 5)
    .map { println("map $it"); it * 2 }
    .filter { println("filter $it"); it > 5 }
// 立即执行所有 map,再执行所有 filter

// Sequence:惰性执行
val sequence = sequenceOf(1, 2, 3, 4, 5)
    .map { println("map $it"); it * 2 }
    .filter { println("filter $it"); it > 5 }
// 不执行任何操作,直到需要结果

二、创建序列 #

2.1 sequenceOf #

kotlin
val sequence = sequenceOf(1, 2, 3, 4, 5)

2.2 asSequence #

kotlin
val list = listOf(1, 2, 3, 4, 5)
val sequence = list.asSequence()

2.3 generateSequence #

kotlin
// 无限序列
val infinite = generateSequence(1) { it + 1 }

// 有限序列
val finite = generateSequence(1) { if (it < 10) it + 1 else null }

// 带条件的无限序列
val odds = generateSequence(1) { it + 2 }.take(5)
// [1, 3, 5, 7, 9]

2.4 sequence 构建器 #

kotlin
val sequence = sequence {
    yield(1)
    yield(2)
    yield(3)
    yieldAll(listOf(4, 5))
}
// [1, 2, 3, 4, 5]

2.5 斐波那契序列 #

kotlin
val fibonacci = sequence {
    var a = 0L
    var b = 1L
    while (true) {
        yield(a)
        val temp = a + b
        a = b
        b = temp
    }
}

fibonacci.take(10).toList()
// [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

三、序列操作 #

3.1 中间操作 #

中间操作返回新的 Sequence,惰性执行:

kotlin
val sequence = sequenceOf(1, 2, 3, 4, 5)
    .map { it * 2 }        // 惰性
    .filter { it > 4 }     // 惰性
    .take(3)               // 惰性
// 此时没有执行任何操作

3.2 终端操作 #

终端操作触发实际计算:

kotlin
val sequence = sequenceOf(1, 2, 3, 4, 5)
    .map { it * 2 }
    .filter { it > 4 }

// 终端操作
sequence.toList()          // [6, 8, 10]
sequence.toSet()           // {6, 8, 10}
sequence.first()           // 6
sequence.count()           // 3
sequence.forEach { println(it) }

3.3 常用操作 #

kotlin
val sequence = sequenceOf(1, 2, 3, 4, 5)

// 映射
sequence.map { it * 2 }
sequence.flatMap { listOf(it, it * 2).asSequence() }

// 过滤
sequence.filter { it > 2 }
sequence.take(3)
sequence.drop(2)
sequence.distinct()

// 排序
sequence.sorted()
sequence.sortedBy { it }

// 聚合
sequence.reduce { acc, n -> acc + n }
sequence.fold(0) { acc, n -> acc + n }
sequence.sum()
sequence.count()

四、惰性求值示例 #

4.1 执行顺序对比 #

kotlin
// List:先完成所有 map,再完成所有 filter
val list = listOf(1, 2, 3, 4, 5)
    .map { println("map: $it"); it * 2 }
    .filter { println("filter: $it"); it > 5 }
    .take(2)
// 输出:
// map: 1, map: 2, map: 3, map: 4, map: 5
// filter: 2, filter: 4, filter: 6, filter: 8, filter: 10

// Sequence:逐个元素处理
val result = listOf(1, 2, 3, 4, 5)
    .asSequence()
    .map { println("map: $it"); it * 2 }
    .filter { println("filter: $it"); it > 5 }
    .take(2)
    .toList()
// 输出:
// map: 1, filter: 2
// map: 2, filter: 4
// map: 3, filter: 6
// map: 4, filter: 8
// 只处理到找到 2 个结果就停止

4.2 无限序列处理 #

kotlin
// 无限序列 + take
val result = generateSequence(1) { it + 1 }
    .filter { it % 2 == 0 }
    .map { it * it }
    .take(5)
    .toList()
// [4, 16, 36, 64, 100]

五、性能对比 #

5.1 大数据量处理 #

kotlin
// List:创建中间集合
val listResult = (1..1_000_000)
    .map { it * 2 }
    .filter { it > 1_000_000 }
    .take(10)
    .toList()
// 创建多个中间列表,内存消耗大

// Sequence:无中间集合
val sequenceResult = (1..1_000_000)
    .asSequence()
    .map { it * 2 }
    .filter { it > 1_000_000 }
    .take(10)
    .toList()
// 不创建中间集合,内存效率高

5.2 何时使用 Sequence #

kotlin
// 适合使用 Sequence:
// 1. 数据量大
// 2. 多个中间操作
// 3. 不需要所有结果(如 take)

// 不适合使用 Sequence:
// 1. 数据量小
// 2. 只有一个操作
// 3. 需要多次遍历结果

六、序列构建器 #

6.1 yield #

kotlin
fun randomNumbers(seed: Int): Sequence<Int> = sequence {
    var current = seed
    while (true) {
        yield(current)
        current = (current * 1103515245 + 12345) and 0x7FFFFFFF
    }
}

randomNumbers(42).take(5).toList()

6.2 yieldAll #

kotlin
fun <T> flatten(sequences: Sequence<Sequence<T>>): Sequence<T> = sequence {
    sequences.forEach { seq ->
        yieldAll(seq)
    }
}

6.3 复杂序列 #

kotlin
fun treeSequence(root: Node): Sequence<Node> = sequence {
    yield(root)
    root.children.forEach { child ->
        yieldAll(treeSequence(child))
    }
}

七、实战示例 #

7.1 文件行处理 #

kotlin
fun processFile(filePath: String): Sequence<String> {
    return File(filePath).useLines { lines ->
        lines
            .filter { it.isNotBlank() }
            .map { it.trim() }
            .filter { !it.startsWith("#") }
    }
}

// 惰性处理,不会一次性加载整个文件
processFile("large_file.txt")
    .take(100)
    .forEach { println(it) }

7.2 分页数据 #

kotlin
fun <T> paginate(
    fetch: (Int) -> List<T>,
    pageSize: Int
): Sequence<T> = sequence {
    var page = 0
    while (true) {
        val items = fetch(page)
        if (items.isEmpty()) break
        yieldAll(items)
        page++
    }
}

// 惰性加载分页数据
val allData = paginate({ page -> api.fetchPage(page) }, 20)
allData.take(50).toList()  // 只加载前 50 条

7.3 素数序列 #

kotlin
fun primes(): Sequence<Int> = sequence {
    val primes = mutableListOf<Int>()
    var current = 2
    
    while (true) {
        var isPrime = true
        for (p in primes) {
            if (p * p > current) break
            if (current % p == 0) {
                isPrime = false
                break
            }
        }
        
        if (isPrime) {
            primes.add(current)
            yield(current)
        }
        current++
    }
}

primes().take(10).toList()
// [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

八、序列 vs List 选择 #

场景 推荐
数据量大 Sequence
多个中间操作 Sequence
只需要部分结果 Sequence
数据量小 List
需要多次遍历 List
需要索引访问 List

九、最佳实践 #

9.1 使用 asSequence 转换 #

kotlin
// 推荐
val result = list.asSequence()
    .map { ... }
    .filter { ... }
    .toList()

// 不推荐(小数据量)
val result = list
    .map { ... }
    .filter { ... }

9.2 注意终端操作 #

kotlin
// 错误:忘记终端操作
val sequence = list.asSequence().map { it * 2 }
// 不会执行任何操作

// 正确
val result = list.asSequence()
    .map { it * 2 }
    .toList()  // 终端操作

十、总结 #

Sequence 要点:

特性 说明
惰性求值 延迟执行
无中间集合 内存效率高
无限序列 支持无限数据
终端操作 触发计算

下一步,让我们学习 协程基础

最后更新:2026-03-27