简体   繁体   English

Java 8 Stream - 过滤和foreach方法不按预期打印

[英]Java 8 Stream - Filter and foreach method not printing as expected

I am executing the following program: 我正在执行以下程序:

Stream.of("d2", "a2", "b1", "b3", "c")
.filter(s -> {
    System.out.println("filter: " + s);
    return true;
})
.forEach(s -> System.out.println("forEach: " + s));

And the output I got is: 我得到的输出是:

filter:  d2
forEach: d2
filter:  a2
forEach: a2
filter:  b1
forEach: b1
filter:  b3
forEach: b3
filter:  c
forEach: c

However, I was expecting the following output: 但是,我期待以下输出:

filter:  d2
filter:  a2
filter:  b1
filter:  b3
filter:  c 
forEach: d2
forEach: a2
forEach: b1
forEach: b3
forEach: c

Meaning, first the filter method loop should have executed completely and then the forEach method loop should have started. 意思是,首先应该完全执行filter方法循环,​​然后才能启动forEach方法循环。

Is there anything I am doing wrong? 有什么我做错了吗?

Your expectation is wrong. 你的期望是错误的。

When the terminal operation forEach is executed, it consumes one element of the Stream at a time. 当执行终端操作forEach ,它一次消耗一个Stream元素。 Each element it consumes has to pass all the intermediate operations of the Stream , which causes filter to be executed on the element just prior to forEach being executed on same element (assuming the element passes the filter ). 每消耗元件具有传递的所有的中间操作Stream ,这会导致filter的元件上刚刚之前执行forEach被同一元件上执行(假设元件经过filter )。

In other words, filter is lazily applied to each element just when the next operation in the Stream pipeline requires its next element (in your case the next operation is forEach ). 换句话说,当Stream管道中的下一个操作需要其下一个元素时(在您的情况下,下一个操作是forEach ), filter被懒惰地应用于每个元素。

This means that if your terminal operation would only require some of the Stream elements to be processed (for example, if you replaced forEach() with findFirst() ), the filter() operation would only be executed until the first element passes it (which in your example means the filter will be executed only for the first element). 这意味着如果你的终端操作只需要处理一些Stream元素(例如,如果你用findFirst()替换了forEach() findFirst() ), filter()操作只会在第一个元素传递之前执行(在您的示例中,这意味着仅针对第一个元素执行过滤器)。

The processing of a Stream will start with a terminal operation and consume one item after another. Stream的处理将从终端操作开始,并逐个使用一个项目。 The advantages are: 优点是:

The program has to calculate only relevant items - if for example only one item is needed, the filter is only called once: 程序必须计算相关项目 - 例如,如果只需要一个项目,则只调用一次filter

Stream.of("d2", "a2", "b1", "b3", "c")
.filter(s -> {
    System.out.println("filter: " + s);
    return true;
})
.findAny()
.ifPresent(s -> System.out.println("forEach: " + s));

Output: 输出:

filter: d2
forEach: d2

You can even create infinte Streams (which would not be possible otherwise): 您甚至可以创建infinte Streams(否则将无法实现):

IntStream.iterate(0, i -> i+1)
.filter(s -> {
    System.out.println("filter: " + s);
    return true;
})
.peek(i -> {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
    }
})
.forEach(s -> System.out.println("forEach: " + s));

Output: 输出:

filter: 0
forEach: 0
filter: 1
forEach: 1
... (up to infinity)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM