Stream.concat错误的解决方法

时间:2017-05-28 21:25:04

标签: java java-8 java-stream

当注释掉Stream.concat时,createLazyStream按预期工作,只有在应用了终端操作时才会初始化它。

但如果您取消注释Stream.concat行,那么即使没有实际使用(未应用终端操作),您也会看到两个流都已初始化

这是java bug,对吗? 什么是变通方法?

@Test
public void testConcat() {

    Stream<Integer> stream = createLazyStream();
    // Stream<Integer> result = Stream.concat(stream, createLazyStream());

}

private Stream<Integer> createLazyStream() {
    return StreamSupport.stream(() -> {

        System.out.println("initializing stream");
        return IntStream.range(1,10).spliterator();

    }, Spliterator.ORDERED, false);
}

1 个答案:

答案 0 :(得分:6)

不评估流,只评估lambda。这是在ConcatSpliterator的构造函数中完成的,以测试新流的大小是否为:

unsized = aSpliterator.estimateSize() + bSpliterator.estimateSize() < 0;

要调用estimateSize,你需要分裂器,所以它调用lambda来获取它。

您可以通过将Thread.dumpStack()添加到lambda:

来查看
java.lang.Exception: Stack trace
    at java.lang.Thread.dumpStack(Thread.java:1333)
    at test.Main.lambda$0(Main.java:19)
    at java.util.stream.StreamSpliterators$DelegatingSpliterator.get(StreamSpliterators.java:513)
    at java.util.stream.StreamSpliterators$DelegatingSpliterator.estimateSize(StreamSpliterators.java:536)
    at java.util.stream.Streams$ConcatSpliterator.<init>(Streams.java:713)
    at java.util.stream.Streams$ConcatSpliterator$OfRef.<init>(Streams.java:781)
    at java.util.stream.Stream.concat(Stream.java:1080)
    at test.Main.main(Main.java:12)

实际上,您的测试存在缺陷。如果要查看是否评估了流,可以在返回之前添加peek

return StreamSupport.stream(() -> {
    return IntStream.range(1,10).peek(i -> System.out.println("peek")).spliterator();

}, Spliterator.ORDERED, false);

现在您将看到取消注释该行时仍然没有输出。

看起来确实有错误的文档(文档中的“错误”)。来自StreamSupport.stream方法(Link)的文档:

  

Supplier.get()方法将在供应商上调用不超过一次,并且仅在流管道的终端操作开始之后。