Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why not chain java.util.stream.Stream#forEach

Tags:

java

java-8

In java 8,java.util.stream.Stream#forEach consider as a replacement for traditional for-loop. But why not this is not chain function.Says it return void instead of Stream<T> it self.

Like this

Arrays
    .stream(Girls.toArray())
    .forEach(Girls::getUp)
    .forEach(Girls::dressUp)
    .filter(/* Top 10 Girls */)
    .forEach(Gay.getMe()::gotGirl)
    .endFilter()// Not an API, but it means remove last filter
    .filter(/* Worst 10 Girls */)
    .forEach(Gay.get(0)::gotGirl)


girls = Arrays
    .stream(Girls.toArray());
girls.forEach(g->{g.getUp();g.dressUp()});
girls.filter(/* Top 10 Girls */)
    .forEach(Gay.getMe()::gotGirl);
girls.filter(/* Worst 10 Girls */)
    .forEach(Gay.get(0)::gotGirl);

The first is nice than second one.But the first one got worse performance.

So, why forEach is not chainable ?

like image 845
wener Avatar asked Jun 14 '14 10:06

wener


2 Answers

The forEach operation is indeed a terminal operation and is thus not chainable, but it is possible to compose several operations (consumers, in this case) into a single forEach call. For example:

    Consumer<String> c1 = s -> System.out.println(s + "1");
    Consumer<String> c2 = s -> System.out.println(s + "2");
    Consumer<String> c3 = s -> System.out.println(s + "3");
    Arrays.asList("a", "b", "c")
          .stream()
          .forEach(c1.andThen(c2).andThen(c3));

Unfortunately it doesn't appear possible to write the lambdas inline without a bunch of ugly casting.

like image 178
Stuart Marks Avatar answered Oct 25 '22 11:10

Stuart Marks


Chaining with andThen is indeed the way to go, but we need some syntactic sugar to make it pretty:

public class Consumers {
    public static <T> Consumer<T> of(Consumer<T> base) {
        return base;
    }
}

This allows us to do:

Arrays.asList("a", "b", "c")
      .stream()
      .forEach(Consumers.of(s -> System.out.println(s + "1"))
                        .andThen(s -> System.out.println(s + "2"))
                        .andThen(s -> System.out.println(s + "3")));

Or (shorter):

Arrays.asList("a", "b", "c")
      .forEach(Consumers.of(s -> System.out.println(s + "1"))
                        .andThen(s -> System.out.println(s + "2"))
                        .andThen(s -> System.out.println(s + "3")));

(since forEachis available directly on the collection)

like image 33
marthursson Avatar answered Oct 25 '22 11:10

marthursson