我读了一些关于如何创建有限Stream
(Finite generated Stream in Java - how to create one?,How do streams stop?)的问题。
答案建议实施Spliterator
。 Spliterator
将实现逻辑如何以及下一个提供的元素(tryAdvance
)。但是还有另外两种非默认方法trySplit
和estimateSize()
,我必须实现它们。
Spliterator
的JavaDoc说:
用于遍历和分区源元素的对象。
Spliterator
覆盖的元素源可以是例如阵列,Collection
,IO通道或生成器函数。 ...Spliterator
API旨在支持有效的并行遍历以及顺序遍历,支持分解以及单元素迭代。 ...
另一方面,我可以实现逻辑如何前进到围绕Stream.Builder
的下一个元素并绕过Spliterator
。在每次推进时,我都会称accept
或add
,最后是build
。所以它看起来很简单。
JavaDoc说什么?
Stream
的可变建设者。这允许通过单独生成元素并将它们添加到Stream
来创建Builder
(没有使用ArrayList
作为临时缓冲区的复制开销。)
使用StreamSupport.stream
我可以使用Spliterator
来获得Stream
。还有一个Builder
将提供Stream
。
什么时候应该/我可以使用Stream.Builder
?
只有当Spliterator
效率不高时(例如因为无法对源进行分区并且无法估计其大小)?
请注意,您可以扩展Spliterators.AbstractSpliterator
。然后,只有tryAdvance
来实现。
因此,实施Spliterator
的复杂性并不高。
根本区别在于,只有在需要新元素时才会调用Spliterator
的tryAdvance
方法。相比之下,Stream.Builder
有一个存储空间,它将填充所有流元素,然后才能获得Stream。
因此,Spliterator
是各种惰性求值的首选,也是您想要遍历的现有存储的首选,以避免复制数据。
当元素的创建是非均匀的时,构建器是第一选择,因此您无法按需创建元素。想想你否则会使用Stream.of(…)
的情况,但事实证明它是不灵活的。
例如。你有Stream.of(a, b, c, d, e)
,但现在事实证明,c
和d
是可选的。所以解决方案是
Stream.Builder<MyType> builder = Stream.builder();
builder.add(a).add(b);
if(someCondition) builder.add(c).add(d);
builder.add(e).build()
/* stream operations */
其他用例是this answer,其中需要Consumer
来查询现有的分裂器,然后将值推回到Stream
,或者this answer,其中没有随机访问的结构(类层次结构)应该以相反的顺序流式传输。
另一方面,我可以实现逻辑如何前进到Stream.Builder周围的下一个元素并绕过Spliterator。在每次推进时,我都会称
accept
或add
,最后是build
。所以它看起来很简单。
是的,不是。这很简单,但我认为您不了解使用模式:
流构建器具有生命周期,该生命周期从构建阶段开始,在此期间可以添加元素,然后转换到构建阶段,之后可能不会添加元素。构建的阶段在调用
build()
方法时开始,该方法创建一个有序的Stream
,其元素是添加到流构建器的元素,按添加顺序排列。
(Qazxswpoi)
特别是不,你不会在任何流前进上调用Javadocs的Stream.Builder
或accept
方法。您需要提前为流提供所有对象。然后你add
得到一个流,它将提供你之前添加的所有对象。这类似于将所有对象添加到build()
,然后调用List
的List
方法。
如果这符合您的目的,您实际上可以有效地做到这一点,那就太好了!但是如果你需要根据需要生成元素,无论是否有限制,那么stream()
无法帮助你。 Stream.Builder
可以。