Java Streams用Supplier连接Streams,后跟distinct(惰性评估行为)



我有一个类似的简单代码

import java.util.function.Supplier;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class StreamSupplierVersusConcat {
public static void main(String[] args) {
final StreamSupplierVersusConcat clazz = new StreamSupplierVersusConcat();
clazz.doConcat();                
}
private void doConcat(){        
System.out.println(Stream.concat(buildStreamFromRange(0,1000).get()
,buildStreamFromRange(1000,2000).get())
.anyMatch("1"::equals));                
}
private Supplier<Stream<String>>buildStreamFromRange(final int start,final int end){
return ()->IntStream.range(start, end)
.mapToObj(i->{
System.out.println("index At: "+i);
return String.valueOf(i);
});
}    
}

我知道concat是懒惰的,所以当我运行代码时,我看到它只生成了两个值,这很好,但知道distinct是一个有状态的操作,我认为把这个方法放在Stream管道上,Stream会生成所有值,然后做anyMatch方法,但如果我把它放成这个

private void doConcat(){        
System.out.println(Stream.concat(buildStreamFromRange(0,1000).get()
,buildStreamFromRange(1000,2000).get())
.distinct()//ARE ALL THE VALUES GENERATED NOT REQUIRED HERE???
.anyMatch("1"::equals));                
}

但有了明显的和没有它,我得到了同样的回应。

index At: 0
index At: 1
true

我错过了什么我认为distinct会在anyMatch看到任何之前看到消耗所有项目经过Java 8测试。

非常感谢。

在恢复我对的理解时,我认为distinct会在anyMatch看到任何之前看到消耗所有项目不正确,这个例子解释了这一点。

private void distinctIsNotABlockingCall(){
final boolean match = Stream.of("0","1","2","3","4","5","6","7","8","8","8","9","9","9","9","9","9","9","9","9","10","10","10","10")
.peek(a->System.out.println("before: "+a))
.distinct()//I THOUGHT THAT NOT ANYMATCH WAS CALLED AFTER DISTINCT HANDLE ALL THE ITEMS BUT WAS WRONG.
.peek(a->System.out.println("after: "+a))
.anyMatch("10"::equals);
System.out.println("match? = " + match);                
}
before: 0
after: 0
before: 1
after: 1
before: 2
after: 2
before: 3
after: 3
before: 4
after: 4
before: 5
after: 5
before: 6
after: 6
before: 7
after: 7
before: 8
after: 8
before: 8 distinct working
before: 8 distinct working
before: 9
after: 9 
before: 9 distinct working
before: 9 distinct working
before: 9 distinct working
before: 9 distinct working
before: 9 distinct working
before: 9 distinct working
before: 9 distinct working
before: 9 distinct working
before: 10
after: 10
match? = true

你可以看到distinct收到了重复和非重复的值,但anyMatch也收到了这些非重复的数值,distinct和anyMatch同时工作,非常感谢。

流是惰性的,因为不计算中间操作除非调用了终端操作。在此处检查SO答案

据我所知,Stream Api流式传输每个元素,直到应用终端操作,然后流式传输下一个元素。

这也将解释这里的情况。元素"0"被流式传输,终端操作不满足。另一个需要流式传输,现在是"1",满足终端操作.anyMatch("1"::equals));。无需再流式传输任何元素。Distinct将在其间调用,而无需更改流式元素。

因此,如果在"0"之后有另一个要流式传输的"0",它将根本无法到达终端操作。

private void doConcat(){        

System.out.println(Stream.concat(buildStreamFromRange(0,1000).get()
,buildStreamFromRange(1000,2000).get())
.distinct()
.peek( e -> System.out.println(e))
.anyMatch("1"::equals));  

尝试添加peek,并尝试在开始时流式传输2个"0"元素。其中只有1个将通过流程并从peek打印出来。

Peek还可用于调试目的,并在您不确定时查看流的行为,因此在将来使用它对您有利。

面向未来读者的简单示例:

一个更简单的例子是,未来的读者将能够理解流中的懒惰运算符是如何工作的:

Stream.of("0","0","1","2","3","4")
.distinct()
.peek(a->System.out.println("after distinct: "+a))
.anyMatch("1"::equals);

将打印

after distinct: 0
after distinct: 1

第一个"0"一直到终端操作,但不满足它。必须流式传输另一个元素。

第二个"0"通过.distinct()进行滤波,并且永远不会到达终端操作

由于还不满足终端操作,所以对下一个元素进行流式传输。

"1"通过终端操作并满足

不再需要对元素进行流式传输。

最新更新