当注释掉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);
}
答案 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()方法将在供应商上调用不超过一次,并且仅在流管道的终端操作开始之后。