List 和 Sequence 的区别
Sequence 中文翻译是序列,相对于 List 这种列表容器,它们最大的区别是:Sequence 是惰性的,它会对每个元素逐个执行所有处理步骤;而 List 不是,它会完成整个集合的每个步骤,然后进行下一步。
以过滤长于三个字符的单词,并输出前四个单词的长度的代码为例。
val words = "The quick brown fox jumps over the lazy dog".split(" ")
val lengthsList = words.filter { println("filter: $it"); it.length > 3 }
.map { println("length: ${it.length}"); it.length }
.take(4)
内部实现过程如下所示。可以看到,它的每一步都会把当前集合的所有元素都处理一遍。
如果换成 Sequence 的实现,它的内部流程如下所示。可以看到,它是从集合中拿一个元素取出来,执行完所有的操作后,再执行下一个元素。
可以看到,当我们使用 Sequence 来实现相同的逻辑时,其代码的执行步骤(18步)相对于使用 List (23步)是明显更少的。因此合理使用 List 和 Sequence 可以提高程序执行的效率。
那么我们什么时候用 List,什么时候用 Sequence 呢?这篇 Kotlin : Slow List and Lazy Sequence 文章详细比较了在不同场景下不同代码执行的效率。感兴趣的话可以看看,这里直接列出文章的结论:
- 不需要执行操作时,使用
List - 只有
map操作时,使用Sequence - 当只有
filter操作时,使用List - 如果以
First结尾,则使用Sequence - 对于运算符的组合或此处未提及的其他运算符,请使用
measureNanoTime进行试验。
Sequence 和 flow 的区别
flow 是 kotlin 提供的一套数据流框架。它的行为与 Sequence 类似,它也是对数据逐个执行所有处理步骤。除此之外,flow 还提供了很多 Sequence 不具备的高级功能:
Sequence内无法使用挂起函数,因此操作时阻塞的,而flow支持挂起函数,可以是非阻塞的flow可以通过flowOn方法切换线程,从而在不同的线程中发送和接收数据;而Sequence不支持Sequence不能不能并行处理数据;而flow可以
简单来说,flow 就是一个加强版的 Sequence,其内部提供了线程、取消、异步和并行处理的支持。但这不意味着我们应该使用 Flow 而不是 Sequence。因为相对于 Flow,Sequence 还是有两点优势的:
Sequence比flow的性能更好。因为Flow需要支持异步执行、线程、并行处理等功能,本身是比较耗时的Sequence比flow支持更多的集合操作符,比如:chunk、windowed、zipWithNext、toIterator、ifEmpty等等
Channel 和 flow 的区别
Channel 也是 Kotlin 中实现跨协程数据传输的数据结构,类似于 Java 中的 BlockQueue 阻塞队列。不同之处是 BlockQueue 会阻塞线程,而 Channel 是挂起线程。 Channel 和 flow 的区别主要有两点,分别是:
Channel只能send(发送)和receive(接收);而flow可以在中间map、fliter等执行各种操作flows会自动地关闭数据流;而Channel需要主动调用close关闭数据流,更容易造成资源泄漏。
因此,在实际开发过程中, Google 在 协程 Flow 最佳实践 | 基于 Android 开发者峰会应用 这篇文章中是建议我们优先使用 flow 而不是 Channel。