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

In java 8, java.util.stream.Stream#forEach seen as a replacement for the traditional for loop. But why not be a chain function. Says that it returns void instead of Stream<T> .

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 pleasant than the second. But the first one got worse performance.

So why is forEach not chained?

+7
java java-8
source share
6 answers

Because forEach is a terminal operation. This makes the thread consume all its elements and call the consumer for each of them. Once this is done, the thread will be consumed and cannot be reused.

A thread has as many intermediate operations as you want, but can only have one terminal operation.

+11
source share

The methods you are looking for exist and are called Stream :: peek and Stream :: map . With Stream::peek , the code above might look like this.

 Arrays .stream(Girls.toArray()) .peek(Girls::getUp) .peek(Girls::dressUp) .filter(/* Top 10 Girls */) .peek(Gay.getMe()::gotGirl) ... 
+19
source share

The forEach operation is indeed a terminal operation and therefore is not connected to a chain, but in this case it is possible to create several operations (in this case, consumers) in one 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 is not possible to write lambdas inline without a bunch of ugly casting.

+5
source share

Continuing from Stuart Marx 's answer , you can write the built-in lambdas, but you just need to choose the first consumer:

 Arrays.asList("a", "b", "c").forEach( ((Consumer<String>) s -> System.out.println(s + "1")) .andThen(s->System.out.println(s + "2")) .andThen(s -> System.out.println(s + "3")) ); 
+3
source share

The chain with andThen really a way to go, but we need some sort of syntactic sugar to make it beautiful:

 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 (in short):

 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 forEach available directly in the collection)

+2
source share

How andThen defined in Java 8 as

 default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } 

you can easily create your own composite Consumer<T> for any number of your functions

 class CompositeConsumer<T> implements Consumer<T> { private final List<Consumer<T>> funcs; CompositeConsumer(List<Consumer<T>> funcs) { this.funcs = funcs; } @Override public void accept(T t) { for (Consumer<T> func: funcs) { func.accept(t); } } } 

and use it for any number of your functions right away

 List<Consumer<String>> funcs = ... Arrays.asList("a", "b", "c") .forEach(new CompositeConsumer(funcs)); 
0
source share

All Articles