Spliterator 与 Stream.Builder
Spliterator vs Stream.Builder
我读了一些关于如何创建有限的问题 Stream
(
, ).
答案建议执行一个Spliterator
。 Spliterator
将实现如何提供以及下一个提供哪个元素的逻辑 (tryAdvance
)。但是还有另外两个非默认方法 trySplit
和 estimateSize()
我必须实现。
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
的逻辑。在每次前进时,我都会调用 accept
或 add
,最后调用 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.Builder
的 accept
或 add
方法。您需要提前为流 in 提供所有对象。然后你 build()
获得一个流,它将提供你之前添加的所有对象。这类似于将所有对象添加到 List
,然后调用 List
的 stream()
方法。
如果这符合您的目的,并且您实际上可以高效地完成它,那就太好了!但是如果你需要按需生成元素,不管有没有限制,那么Stream.Builder
就帮不了你了。 Spliterator
可以。
请注意,您可以扩展 Spliterators.AbstractSpliterator
。那么,就只有tryAdvance
要执行了。
所以实现一个Spliterator
的复杂度并不高
根本区别在于 Spliterator
的 tryAdvance
方法仅在需要新元素时调用。相比之下,Stream.Builder
有一个 storage,在您获取 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 */
其他用例是 , 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 进行比较相同。
我读了一些关于如何创建有限的问题 Stream
(
答案建议执行一个Spliterator
。 Spliterator
将实现如何提供以及下一个提供哪个元素的逻辑 (tryAdvance
)。但是还有另外两个非默认方法 trySplit
和 estimateSize()
我必须实现。
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, aCollection
, an IO channel, or a generator function. ... TheSpliterator
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
的逻辑。在每次前进时,我都会调用 accept
或 add
,最后调用 build
。所以看起来很简单。
JavaDoc 说了什么?
A mutable builder for a
Stream
. This allows the creation of aStream
by generating elements individually and adding them to theBuilder
(without the copying overhead that comes from using anArrayList
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
oradd
and at the endbuild
. 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 orderedStream
whose elements are the elements that were added to the stream builder, in the order they were added.
(Javadocs)
特别是不,您不会在任何流提前调用 Stream.Builder
的 accept
或 add
方法。您需要提前为流 in 提供所有对象。然后你 build()
获得一个流,它将提供你之前添加的所有对象。这类似于将所有对象添加到 List
,然后调用 List
的 stream()
方法。
如果这符合您的目的,并且您实际上可以高效地完成它,那就太好了!但是如果你需要按需生成元素,不管有没有限制,那么Stream.Builder
就帮不了你了。 Spliterator
可以。
请注意,您可以扩展 Spliterators.AbstractSpliterator
。那么,就只有tryAdvance
要执行了。
所以实现一个Spliterator
的复杂度并不高
根本区别在于 Spliterator
的 tryAdvance
方法仅在需要新元素时调用。相比之下,Stream.Builder
有一个 storage,在您获取 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 */
其他用例是 Consumer
was needed to query an existing spliterator and push the value back to a Stream
afterwards, or
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 进行比较相同。