【问题标题】:Java Streams concat Streams with Supplier followed by distinct (lazy evaluation behavior)Java Streams concat Streams with Supplier 后跟 distinct(惰性求值行为)
【发布时间】:2021-09-26 12:32:25
【问题描述】:

我有一个这样的简单代码

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 是惰性的,所以当我运行代码时,我看到它只生成 2 个很棒的值,但知道 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 看到 any 之前看到所有项目。这个例子解释它是不正确的。

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 正在同时工作,非常感谢。

【问题讨论】:

    标签: java java-8 java-stream distinct-values


    【解决方案1】:

    流是惰性的,因为不评估中间操作 除非调用终端操作。 check SO answer here

    据我所知,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"经过终端操作,满足。

    不再需要流式传输元素。

    【讨论】:

    • 我认为 distinct 会在 anyMatch 看到之前消耗所有项目..
    • 谢谢队友,我现在明白了,我认为 distinct 需要处理所有值,然后 anyMatch 才能与任何匹配,但我错了,谢谢队友,我真的很感谢你的帮助。
    猜你喜欢
    • 2015-06-19
    • 1970-01-01
    • 2019-01-27
    • 2018-11-07
    • 2020-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-28
    相关资源
    最近更新 更多