Kotlin中的集合和序列你更喜欢使用哪一个

86 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第29天,点击查看活动详情

Kotlin中的集合和序列你更喜欢使用哪一个

我们在日常的Kotlin的开发中,我们很多情况下都比较偏向于使用集合,但往往都忽略了还有一个和集合具有相同功能的Sequences,他俩在使用的时候姿势都非常相似,但是执行的时候就存在着巨大的差异。接下来我们了解下两者之间的区别、您应该在何时使用哪一个,以及它们对性能的影响是什么。

Collections 和Sequences

Collections的每一个操作在它被调用时立刻就会被执行,并且操作的结果会存储到一个新的集合中。我们可以看下map的实现是怎么样的

public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
    return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}
public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.mapTo(destination: C, transform: (T) -> R): C {
    for (item in this)
        destination.add(transform(item))
    return destination
}

可以看到map操作会将转换的结果放到新的集合中返回

Sequences的每一个操作都是惰性操作,这种特性与Flow的冷流有点相似,只有Sequences的末端操作符的操作才会让中间操作符的操作生效。并且Seqences是基于原始集合的迭代器创建的。

public fun <T, R> Sequence<T>.map(transform: (T) -> R): Sequence<R> {
    return TransformingSequence(this, transform)
}

那么我们怎么去区分末端操作符和中间操作符呢?Sequences中间操作符会返回一个Sequences,末端操作符会返回一个Unit

下面我们通过一个示例来看下区别

Collection:

fun main() {
    listOf(1,2,3)
        .map {
            println("map $it")
            it
        }.filter {
            println("filter $it")
            it %2 ==0
        }
}
控制台输出:
map 1
map 2
map 3
filter 1
filter 2
filter 3

Sequences:

fun main() {
    listOf(1,2,3)
        .asSequence()
        .map {
            println("map $it")
            it
        }.filter {
            println("filter $it")
            it %2 ==0
        }.forEach {
            println("forEach $it")
        }
}
控制台:
map 1
filter 1
map 2
filter 2
forEach 2
map 3
filter 3

我们通过上面的操作就能很明显的看出差别:

  • 操作符的单位:Collection的操作符操作的是整个集合的每一个元素,Sequences是每一个元素是逐个执行每一个操作
  • 当我们把Sequences的forEach操作符去掉之后,会发现控制台什么都不会输出,这个就是Sequences的惰性操作,而集合的每一个操作都是积极的

Collection的每个操作符都会创建一个新的集合然后使用该集合的迭代器进行操作,但是Sequences的所有操作都封装进同一个迭代器里面,然后通过末端操作符去执行迭代器的next()方法。

使用场景

Koltin的CollectionAPI在处理一些量级小的数据的时候,速度和性能都会优于Sequences.但是一旦数据的量级变得庞大就会发现Sequences的性能和处理速度会变的比较明显。还有就是我们上面分析过collection在每使用一个操作符时都会创建一个集合,那么我们在对某个集合进行大量操作的时候就会导致在相同的情况下Sequences的内存开销要优于Collection。