Advertisement
Advertisement


Break or return from Java 8 stream forEach?


Question

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?
})
2016/11/13
1
319
11/13/2016 6:06:43 PM

Accepted Answer

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);
2016/03/17
387
3/17/2016 1:49:49 PM

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
}
2018/08/06

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;
   }
})
2016/05/25

Below you find the solution I used in a project. Instead forEach just use allMatch:

someObjects.allMatch(obj -> {
    return !some_condition_met;
});
2015/12/23

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.

2014/04/26

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));
2015/06/02