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

家住魔仙堡 提交于 2019-12-21 02:40:44

问题


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.

Is there anything I am doing wrong?


回答1:


Your expectation is wrong.

When the terminal operation forEach is executed, it consumes one element of the Stream at a time. 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).

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).

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).




回答2:


The processing of a Stream will start with a terminal operation and consume one item after another. 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:

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):

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)


来源:https://stackoverflow.com/questions/40863739/java-8-stream-filter-and-foreach-method-not-printing-as-expected

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!