Spliterator 与 Stream.Builder

Spliterator vs Stream.Builder

我读了一些关于如何创建有限的问题 Stream ( , ).

答案建议执行一个SpliteratorSpliterator 将实现如何提供以及下一个提供哪个元素的逻辑 (tryAdvance)。但是还有另外两个非默认方法 trySplitestimateSize() 我必须实现。

Spliterator 的 JavaDoc 说:

An object for traversing and partitioning elements of a source. The source of elements covered by a Spliterator could be, for example, an array, a Collection, an IO channel, or a generator function. ... The Spliterator API was designed to support efficient parallel traversal in addition to sequential traversal, by supporting decomposition as well as single-element iteration. ...

另一方面,我可以实现如何前进到 Stream.Builder 周围的下一个元素并绕过 Spliterator 的逻辑。在每次前进时,我都会调用 acceptadd,最后调用 build。所以看起来很简单。

JavaDoc 说了什么?

A mutable builder for a Stream. This allows the creation of a Stream by generating elements individually and adding them to the Builder (without the copying overhead that comes from using an ArrayList as a temporary buffer.)

使用 StreamSupport.stream 我可以使用 Spliterator 获得 Stream。而且 Builder 将提供 Stream.

我什么时候应该/可以使用 Stream.Builder
仅当 Spliterator 不会更有效时(例如,因为源无法分区且无法估计其大小)?

On the other hand I could implement the logic how to advance to the next element around a Stream.Builder and bypass a Spliterator. On every advance I would call accept or add and at the end build. So it looks quite simple.

是也不是。它简单,但我认为您不了解使用模型:

A stream builder has a lifecycle, which starts in a building phase, during which elements can be added, and then transitions to a built phase, after which elements may not be added. The built phase begins when the build() method is called, which creates an ordered Stream whose elements are the elements that were added to the stream builder, in the order they were added.

(Javadocs)

特别是不,您不会在任何流提前调用 Stream.Builderacceptadd 方法。您需要提前为流 in 提供所有对象。然后你 build() 获得一个流,它将提供你之前添加的所有对象。这类似于将所有对象添加到 List,然后调用 Liststream() 方法。

如果这符合您的目的,并且您实际上可以高效地完成它,那就太好了!但是如果你需要按需生成元素,不管有没有限制,那么Stream.Builder就帮不了你了。 Spliterator可以。

请注意,您可以扩展 Spliterators.AbstractSpliterator。那么,就只有tryAdvance要执行了。

所以实现一个Spliterator的复杂度并不高

根本区别在于 SpliteratortryAdvance 方法仅在需要新元素时调用。相比之下,Stream.Builder 有一个 storage,在您获取 Stream 之前,它将填充所有流元素。

所以 Spliterator 是各种懒惰求值的首选,以及当你有一个现有的存储要遍历时,以避免复制数据。

构建器是元素创建不统一时的首选,无法表达按需创建元素。想一想您本来会使用 Stream.of(…) 的情况,但事实证明它太不灵活了。

例如你有 Stream.of(a, b, c, d, e),但现在发现 cd 是可选的。所以解决方案是

Stream.Builder<MyType> builder = Stream.builder();
builder.add(a).add(b);
if(someCondition) builder.add(c).add(d);
builder.add(e).build()
   /* stream operations */

其他用例是 , where a Consumer was needed to query an existing spliterator and push the value back to a Stream afterwards, or ,其中没有随机访问的结构(class 层次结构)应该以相反的顺序流式传输。

Stream.Builder 是用词不当,因为无法真正构建流。可以构建的东西是值对象——dto、数组、集合。 所以如果 Stream.Builder 被认为是一个缓冲区,它可能有助于更好地理解它,例如:

buffer.add(a)
buffer.add(b)
buffer.stream()

这表明它与 ArrayList 有多么相似:

list.add(a)
list.add(b)
list.stream()

另一方面,Spliterator 是流的基础,允许在数据集上进行高效导航(迭代器的改进版本)。

所以答案是不应该比较它们。将 Stream.Builder 与 Spliterator 进行比较与将 ArrayList 与 Spliterator 进行比较相同。