Reputation: 29806
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?
})
Upvotes: 433
Views: 523215
Reputation: 1254
Update with Java 9+ with takeWhile
:
AtomicBoolean ongoing = new AtomicBoolean(true);
someobjects.stream()...takeWhile(t -> ongoing.get()).forEach(t -> {
// doing something.
if (...) { // want to break;
ongoing.set(false);
}
});
Upvotes: 28
Reputation: 51
You would use .map for this and return a boolean to indicate a break
someObjects.map(obj -> {
if (some_condition_met) {
return true;
}
return false;
}).filter(Boolean.booleanValue).findAny();
findAny() is a short-circuiting terminal operation, thus the moment the filter passes an item (true) findFirst will break the operation.
An even shorter operation would be calling anyMatch instead of map as below:
someObjects.anyMatch(obj -> {
if (some_condition_met) {
return true;
}
return false;
});
as anyMatch is also a short-circuit operation.
Upvotes: 1
Reputation: 81
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");
}
Upvotes: 8
Reputation: 125
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/
Upvotes: 1
Reputation: 669
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.
Upvotes: 1
Reputation: 22671
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.
Upvotes: 0
Reputation: 20026
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
}
Upvotes: 61
Reputation: 331
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>
});
Upvotes: 3
Reputation: 4153
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;
}
})
Upvotes: 87
Reputation: 206816
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);
Upvotes: 487
Reputation: 4016
Below you find the solution I used in a project. Instead forEach
just use allMatch
:
someObjects.allMatch(obj -> {
return !some_condition_met;
});
Upvotes: 31
Reputation: 6627
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;
}
Upvotes: 3
Reputation: 5112
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));
Upvotes: 11
Reputation: 19260
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.
Upvotes: 7
Reputation: 1500515
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.
Upvotes: 13