简体   繁体   中英

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.

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

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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