这两个接口(interface)仅定义一种方法
public operator fun iterator(): Iterator<T>
文档说
Sequence
是懒惰的。但是Iterable
是否也懒惰(除非有Collection
支持)? 最佳答案
关键区别在于Iterable<T>
和Sequence<T>
的语义和stdlib扩展功能的实现。
Sequence<T>
,扩展功能在可能的情况下延迟执行,类似于Java Streams中间操作。例如, Sequence<T>.map { ... }
返回另一个Sequence<R>
,并且在调用toList
或fold
之类的终端操作之前,不会实际处理这些项。考虑以下代码:
val seq = sequenceOf(1, 2)
val seqMapped: Sequence<Int> = seq.map { print("$it "); it * it } // intermediate
print("before sum ")
val sum = seqMapped.sum() // terminal
它打印:
before sum 1 2
当您想要尽可能减少终端操作中完成的工作时,
Sequence<T>
用于懒惰使用和高效的流水线操作,与Java Streams相同。但是,懒惰会带来一些开销,这对于较小的collection的常见简单转换是不希望的,并且会使它们的性能降低。通常,没有确定何时需要它的好方法,因此在Kotlin中,将stdlib懒惰明确化并提取到
Sequence<T>
接口(interface),以避免默认情况下在所有Iterable
上使用它。 Iterable<T>
来说,具有中间操作语义的扩展功能很忙,可以立即处理这些项目并返回另一个Iterable
。例如, Iterable<T>.map { ... }
返回带有映射结果的List<R>
。等效的Iterable代码:
val lst = listOf(1, 2)
val lstMapped: List<Int> = lst.map { print("$it "); it * it }
print("before sum ")
val sum = lstMapped.sum()
打印输出:
1 2 before sum
如上所述,默认情况下
Iterable<T>
是非惰性的,并且此解决方案很好地展示了自己:在大多数情况下,它的locality of reference很好,因此可以利用CPU缓存,预测,预取等优势,因此即使对集合进行多次复制也仍然足够好并在简单的情况下(小收藏集)表现更好。如果需要对评估管道进行更多控制,则可以使用
Iterable<T>.asSequence()
函数将其显式转换为惰性序列。 关于kotlin - Kotlin的Iterable和Sequence看起来完全一样。为什么需要两种类型?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44703690/