Break or return from Java 8 stream forEach?
JavaForeachLambdaJava 8Java Problem Overview
When using external iteration over an Iterable
we use break
or return
from enhanced for-each loop as:
for (SomeObject obj : someObjects) {
if (some_condition_met) {
break; // or return obj
}
}
How can we break
or return
using the internal iteration in a Java 8 lambda expression like:
someObjects.forEach(obj -> {
//what to do here?
})
Java Solutions
Solution 1 - Java
If you need this, you shouldn't use forEach
, but one of the other methods available on streams; which one, depends on what your goal is.
For example, if the goal of this loop is to find the first element which matches some predicate:
Optional<SomeObject> result =
someObjects.stream().filter(obj -> some_condition_met).findFirst();
(Note: This will not iterate the whole collection, because streams are lazily evaluated - it will stop at the first object that matches the condition).
If you just want to know if there's an element in the collection for which the condition is true, you could use anyMatch
:
boolean result = someObjects.stream().anyMatch(obj -> some_condition_met);
Solution 2 - Java
A return in a lambda equals a continue in a for-each, but there is no equivalent to a break. You can just do a return to continue:
someObjects.forEach(obj -> {
if (some_condition_met) {
return;
}
})
Solution 3 - Java
This is possible for Iterable.forEach()
(but not reliably with Stream.forEach()
). The solution is not nice, but it is possible.
WARNING: You should not use it for controlling business logic, but purely for handling an exceptional situation which occurs during the execution of the forEach()
. Such as a resource suddenly stops being accessible, one of the processed objects is violating a contract (e.g. contract says that all the elements in the stream must not be null
but suddenly and unexpectedly one of them is null
) etc.
According to the documentation for Iterable.forEach()
:
> Performs the given action for each element of the Iterable
until all elements have been processed or the action throws an exception... Exceptions thrown by the action are relayed to the caller.
So you throw an exception which will immediately break the internal loop.
The code will be something like this - I cannot say I like it but it works. You create your own class BreakException
which extends RuntimeException
.
try {
someObjects.forEach(obj -> {
// some useful code here
if(some_exceptional_condition_met) {
throw new BreakException();
}
}
}
catch (BreakException e) {
// here you know that your condition has been met at least once
}
Notice that the try...catch
is not around the lambda expression, but rather around the whole forEach()
method. To make it more visible, see the following transcription of the code which shows it more clearly:
Consumer<? super SomeObject> action = obj -> {
// some useful code here
if(some_exceptional_condition_met) {
throw new BreakException();
}
});
try {
someObjects.forEach(action);
}
catch (BreakException e) {
// here you know that your condition has been met at least once
}
Solution 4 - Java
Below you find the solution I used in a project. Instead forEach
just use allMatch
:
someObjects.allMatch(obj -> {
return !some_condition_met;
});
Solution 5 - Java
Either you need to use a method which uses a predicate indicating whether to keep going (so it has the break instead) or you need to throw an exception - which is a very ugly approach, of course.
So you could write a forEachConditional
method like this:
public static <T> void forEachConditional(Iterable<T> source,
Predicate<T> action) {
for (T item : source) {
if (!action.test(item)) {
break;
}
}
}
Rather than Predicate<T>
, you might want to define your own functional interface with the same general method (something taking a T
and returning a bool
) but with names that indicate the expectation more clearly - Predicate<T>
isn't ideal here.
Solution 6 - Java
Update with Java 9+ with takeWhile
:
MutableBoolean ongoing = MutableBoolean.of(true);
someobjects.stream()...takeWhile(t -> ongoing.value()).forEach(t -> {
// doing something.
if (...) { // want to break;
ongoing.setFalse();
}
});
Solution 7 - Java
You can use java8 + rxjava.
//import java.util.stream.IntStream;
//import rx.Observable;
IntStream intStream = IntStream.range(1,10000000);
Observable.from(() -> intStream.iterator())
.takeWhile(n -> n < 10)
.forEach(n-> System.out.println(n));
Solution 8 - Java
For maximal performance in parallel operations use findAny() which is similar to findFirst().
Optional<SomeObject> result =
someObjects.stream().filter(obj -> some_condition_met).findAny();
However If a stable result is desired, use findFirst() instead.
Also note that matching patterns (anyMatch()/allMatch) will return only boolean, you will not get matched object.
Solution 9 - Java
I have achieved by something like this
private void doSomething() {
List<Action> actions = actionRepository.findAll();
boolean actionHasFormFields = actions.stream().anyMatch(actionHasMyFieldsPredicate());
if (actionHasFormFields){
context.addError(someError);
}
}
}
private Predicate<Action> actionHasMyFieldsPredicate(){
return action -> action.getMyField1() != null;
}
Solution 10 - Java
You can achieve that using a mix of peek(..) and anyMatch(..).
Using your example:
someObjects.stream().peek(obj -> {
<your code here>
}).anyMatch(obj -> !<some_condition_met>);
Or just write a generic util method:
public static <T> void streamWhile(Stream<T> stream, Predicate<? super T> predicate, Consumer<? super T> consumer) {
stream.peek(consumer).anyMatch(predicate.negate());
}
And then use it, like this:
streamWhile(someObjects.stream(), obj -> <some_condition_met>, obj -> {
<your code here>
});
Solution 11 - Java
int valueToMatch = 7;
Stream.of(1,2,3,4,5,6,7,8).anyMatch(val->{
boolean isMatch = val == valueToMatch;
if(isMatch) {
/*Do whatever you want...*/
System.out.println(val);
}
return isMatch;
});
It will do only operation where it find match, and after find match it stop it's iteration.
Solution 12 - Java
public static void main(String[] args) {
List<String> list = Arrays.asList("one", "two", "three", "seven", "nine");
AtomicBoolean yes = new AtomicBoolean(true);
list.stream().takeWhile(value -> yes.get()).forEach(value -> {
System.out.println("prior cond" + value);
if (value.equals("two")) {
System.out.println(value);
yes.set(false);
}
});
//System.out.println("Hello World");
}
Solution 13 - Java
What about this one:
final BooleanWrapper condition = new BooleanWrapper();
someObjects.forEach(obj -> {
if (condition.ok()) {
// YOUR CODE to control
condition.stop();
}
});
Where BooleanWrapper
is a class you must implement to control the flow.
Solution 14 - Java
I would suggest using anyMatch. Example:-
return someObjects.stream().anyMatch(obj ->
some_condition_met;
);
You can refer this post for understanding anyMatch:- https://beginnersbook.com/2017/11/java-8-stream-anymatch-example/