Java 8 apply function to all elements of Stream without breaking stream chain
Solution 1:
There are (at least) 3 ways. For the sake of example code, I've assumed you want to call 2 consumer methods methodA
and methodB
:
A. Use peek()
:
list.stream().peek(x -> methodA(x)).forEach(x -> methodB(x));
Although the docs say only use it for "debug", it works (and it's in production right now)
B. Use map()
to call methodA, then return the element back to the stream:
list.stream().map(x -> {method1(x); return x;}).forEach(x -> methodB(x));
This is probably the most "acceptable" approach.
C. Do two things in the forEach()
:
list.stream().forEach(x -> {method1(x); methodB(x);});
This is the least flexible and may not suit your need.
Solution 2:
You are looking for the Stream
's map()
function.
example:
List<String> strings = stream
.map(Object::toString)
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
Solution 3:
The best option you have is to apply the map to your stream. which returns a stream consisting of the results of applying the given function to the elements of the stream. For example:
IntStream.range(1, 100)
.boxed()
.map(item->item+3)
.map(item->item*2)...
We are applying several modifications to the stream but in some case we don't want to modify the stream. We just want to visit every element and then pass it down the stream without modification (like the peek() method in the streams API). in such cases, we can
StreamItem peekyMethod(StreamItem streamItemX) {
// .... visit the streamItemX
//Then pass it down the stream
return streamItemX;
}
Solution 4:
Not entirely sure what you mean by breaking the stream chain
, but any operation on a Stream
that returns a Stream
will not break or consume your Stream. Streams are consumed by terminal operations
and as you noted the forEach
does not return a Stream<T>
and as such ends the stream, by executing all the intermediate
operations before the forEach and the forEach itself.
In the example that you provided in the comments:
myStream.map(obj -> {obj.foo(); return obj;}
You can't really do this with one liner. Of course you could use a method reference, but then your returned Stream
would be of a different type (assuming foo
returns a type):
myStream.map(Obj::foo) // this will turn into Stream<T>, where T is
// the return type of foo, instead of Stream<Obj>
Besides that your map
operation is stateful
, which is strongly discouraged. Your code will compile and might even work as you want it to - but it might later fail. map
operations should be stateless
.