Streams:在concat之后停止崩溃

时间:2015-08-18 23:25:38

标签: java java-8 java-stream

我有一些代码如下:

Stream a = Streams.from(...).map(...);
Stream b = Streams.from(...);
Stream c = Stream.concat(a, b);
c.toArray();

Streams.from(Iterable)从迭代中创建一个流 - 看作Iterable#stream()不存在)

最后一行崩溃,例外:

Exception in thread "main" java.lang.IllegalStateException: Accept exceeded fixed size of 266
    at java.util.stream.Nodes$FixedNodeBuilder.accept(Nodes.java:1224)
    at java.util.Iterator.forEachRemaining(Iterator.java:116)
    at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
    at java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:743)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:512)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:502)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:576)
    at java.util.stream.AbstractPipeline.evaluateToArrayNode(AbstractPipeline.java:255)
    at java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:438)
    at ... (my code)

266实际上是流a的大小。流b是11个元素。

我做了一些测试。从代码中删除map(...)使其有效。 以下最小示例也有效:

Stream x = Stream.of(1, 2).map(w -> w + 1);
Stream y = Stream.of(3, 4);
Stream z = Stream.concat(x, y);
z.toArray();

此时我非常怀疑我的映射功能,但是这很好用:

Object[] a = Streams.from(...).map(...).toArray();
Object[] b = Streams.from(...).toArray();
Object[] c = ArrayUtils.addAll(a, b);

是否存在可以解释这种奇怪行为的流API细微之处?

可能有必要提一下,流b是从一个集合构造的,该集合在调用映射函数时会被填充。

1 个答案:

答案 0 :(得分:1)

似乎您的流b的源集合未正确实现,因为它使用Collection.spliterator()的默认实现,该实现假定在流操作期间未修改Collection(特别是其{ {1}}不会改变)。在你的情况下,这似乎是错误的。

如果没有看到您的收藏集的完整代码,提出修复程序就不那么容易了。如果在您的情况下可能,您可以在调用size()方法时执行初始化,因此在遍历集合之前调用size()将返回正确的大小(当前它似乎返回0 )。另一种方法是覆盖size()方法,如下所示:

spliterator()

这样就不会报告public Spliterator<E> spliterator() { return Spliterators.spliteratorUnknownSize(this.iterator(), Spliterator.ORDERED); } 特征,并且流管道不会依赖于大小。现在SIZED可能会运行得更慢,因为阵列重新分配可能是必要的,但它可以正常工作。