Sometimes when processing a Java stream() I find myself in need of a non-terminal forEach() to be used to trigger a side effect but without terminating processing.
I sus
No, there is not.
peek()
will only operate on all elements when forced to by a following operation. Can you predict what will be printed by this code?
public class Test
{
private static final AtomicBoolean FLAG = new AtomicBoolean(false);
private static void setFlagIfGreaterThanZero(int val)
{
if (val > 0) {
FLAG.set(true);
}
}
public static void main(String[] args)
{
FLAG.set(false);
// Test 1
IntStream.range(0, 10)
.peek(Test::setFlagIfGreaterThanZero)
.findFirst();
System.out.println(FLAG.get());
FLAG.set(false);
// Test 2
IntStream.range(0, 10)
.peek(Test::setFlagIfGreaterThanZero)
.sorted()
.findFirst();
System.out.println(FLAG.get());
FLAG.set(false);
// Test 3
IntStream.range(0, 10)
.boxed()
.peek(Test::setFlagIfGreaterThanZero)
.sorted()
.findFirst();
System.out.println(FLAG.get());
FLAG.set(false);
// Test 4
IntStream.range(0, 10)
.peek(Test::setFlagIfGreaterThanZero)
.filter(x -> x == 0)
.toArray();
System.out.println(FLAG.get());
}
}
The answer is:
false
false
true
true
That output might be intuitive if you have a solid understanding of Java Streams, but hopefully it also indicates that it's a very bad idea to rely on peek()
as a mid-stream forEach()
.
map()
also suffers the same issue. As far as I'm aware, there is no Stream operation that guarantees a sort of "process every element without taking shortcuts" behavior in every case independent of the prior and following operations.
Although this can be a pain, the short-circuiting behavior of Streams is an important feature. You might find this excellent answer to be useful: https://stackoverflow.com/a/32194320/507761