腾讯视频连接:html
v.qq.com/x/page/d093…android
Bilibili 视频连接:git
www.bilibili.com/video/av977…github
当即执行和延迟执行的区别在于每次对集合进行转换时,这个操做会在什么时候真正执行。api
Collection(也称集合) 是在每次操做时当即执行的,执行结果会存储到一个新的集合中。做用于 Collection 的转换操做是内联函数。例如,map 的实现方式,能够看到它是一个建立了新 ArrayList 的内联函数:bash
public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}
复制代码
Sequence (也称序列) 是延迟执行的,它有两种类型: 中间操做 (intermediate) 和末端操做(terminal)。中间操做不会当即执行,它们只是被存储起来,仅当末端操做被调用时,才会按照顺序在每一个元素上执行中间操做,而后执行末端操做。中间操做 (好比 map、distinct、groupBy 等) 会返回另外一个Sequence,而末端操做 (好比 first、toList、count 等) 则不会。jvm
Sequence 是不会保留对集合项目的引用的。它基于原始集合的迭代器 (iterator) 建立,而且保留要执行的全部中间操做的引用。ide
与在 Collection 中执行转换操做不一样,Sequence 执行的中间转换不是内联函数,由于内联函数没法存储,而 Sequence 须要存储它们。咱们能够经过下列代码看到像 map 这样的中间操做是如何实现的,能够看到转换函数会存储在一个新的 Sequence 实例中:函数
public fun <T, R> Sequence<T>.map(transform: (T) -> R): Sequence<R>{
return TransformingSequence(this, transform)
}
复制代码
例如 first 这样的末端操做,会对 Sequence 中的元素进行遍历,直到预置条件匹配为止。性能
public inline fun <T> Sequence<T>.first(predicate: (T) -> Boolean): T {
for (element in this) if (predicate(element)) return element
throw NoSuchElementException(“Sequence contains no element matching the predicate.”)
}
复制代码
若是观察 TransformingSequence 这样的类型是如何实现的,咱们会发如今迭代器上调用 next 时,转换存储操做也一并被应用。
internal class TransformingIndexedSequence<T, R>
constructor(private val sequence: Sequence<T>, private val transformer: (Int, T) -> R) : Sequence<R> {
override fun iterator(): Iterator<R> = object : Iterator<R> {
…
override fun next(): R {
return transformer(checkIndexOverflow(index++), iterator.next())
}
…
}
复制代码
不管您使用 Collection 仍是 Sequence,Kotlin 标准库都提供了相似于 find、filter、groupBy 等一系列操做,在使用它们以前,您得确保了解这些操做。
Collections
Sequences
使用 Sequence 时不会去建立中间集合,因为项目会被逐个执行,map 操做只会做用到部分输入上。
转换的顺序
不管您使用 Collection 仍是 Sequence,转换的顺序都很重要。在上面的例子中,first 不须要先在 map 以后进行操做,由于 first 不须要 map 操做的结果就可以执行。若是咱们颠倒业务逻辑的顺序,先把 first 做用到 Collection 上,再对结果执行转换,那么咱们只会建立一个新的对象 —— 一个黄色的正方形。当使用 Sequence 时,会避免建立两个新对象,而当使用 Collection 时则会避免建立整个列表。
内联和大数据集所带来的影响
Collection 的操做使用了内联函数,因此处理所用到的字节码以及传递给它的 lambda 字节码都会进行内联操做。而 Sequence 不使用内联函数,所以,它会为每一个操做建立新的 Function 对象。
另外,Collection 会为每一个转换操做建立一个新的列表,而 Sequence 仅仅是保留对转换函数的引用。
当对数据量小的 Collection 执行 1 到 2 个操做时,上面所说的差别并不会带来什么样的影响,因此这种状况下使用Collection 是没问题的。而当列表数据很大时,中间集合的建立会很消耗资源,这种状况下就应该使用 Sequence。
不幸的是,我不知道有什么样的基准测试可以帮助咱们更好地探索出具体不一样大小的集合或者操做链才会对 Collection 和 Sequence 产生影响。
综上所述,Collection 会当即执行对数据的操做,而 Sequence 则是延迟执行。根据要处理的数据量大小,选择最合适的一个: 数据量小,则使用 Collection,数据量大,则使用 Sequence,另外,需注意操做顺序带来的影响。
点击这里了解更多关于用 Kotlin 进行 Android 开发的相关资料