435

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?
})
4
  • 15
    You can't. Just use a real for statement. Commented Apr 26, 2014 at 7:51
  • 1
    possible duplicate of Java 8: Limit infinite stream by a predicate Commented Apr 26, 2014 at 20:25
  • Consider another approach, you just want to not execute code, so, a simple if condition inside the forEach will do the trick. Commented Jan 4, 2018 at 12:13
  • With Java 9 per stackoverflow.com/questions/20746429/… Commented Jan 26, 2024 at 16:30

15 Answers 15

489

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);
Sign up to request clarification or add additional context in comments.

10 Comments

This works if finding an object was the goal, but that goal is usually served by a return statement from a findSomething method. break is more usually associated with a take while-kind of operation.
@MarkoTopolnik Yes, the original poster has not given us sufficient information to know what exactly the goal is; a "take while" is a third possibility besides the two I mentioned. (Is there a simple way to do "take while" with streams?).
What about when the goal is to properly implement cancel behavior? Is the best thing we can do just to throw a runtime exception inside the forEach lambda when we notice that the user requested a cancel?
@HonzaZidek Edited, but the point is not whether it's possible or not, but what the right way is to do things. You shouldn't try to force using forEach for this; you should use another, more appropriate method instead.
@Jesper I agree with you, I wrote that I did not like the "Exception solution". However your wording "This is not possible with forEach" was technically incorrect. I also prefer your solution, however I can imagine use cases where the solution provided in my answer is preferable: when the loop should be ended because of a real exception. I agree that you should not generally use the exceptions to control the flow.
|
88

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;
   }
})

4 Comments

Nice and idiomatic solution to address the general requirement. The accepted answer extrapolates the requirement.
in other words this does not "Break or return from Java 8 stream forEach" which was the actual question
This will still "pull" records through the source stream though, which is bad if you're paging through some sort of remote dataset.
but that is basically the same as doing if (!some_condition_met) { do_stuff; } (where do_stuff is missing in your code), so the better (IMO) solution with streams would be to use a filter() before forEach()
61

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
}

6 Comments

I think this is a bad practice and should not be considered as a solution to the problem. It is dangerous as it could be misleading for a beginner. According to Effective Java 2nd Edition, Chapter 9, Item 57 : ' Use exceptions only for exceptional conditions'. Furthermore 'Use runtime exceptions to indicate programming errors'. In definitive, I strongly encourage anyone considering this solution to look into @Jesper solution.
@LouisF. I explicitly said "I cannot say I like it but it works". The OP asked "how to break from forEach()" and this is an answer. I fully agree that this should not be used to control the business logic. However I can imagine some useful use cases, like that a connection to a resource suddenly not available in the middle of forEach() or so, for which using exception is not bad practice. I have added a paragraph to my answer to be clear.
I think this is a fine solution. After searching Google for "java exceptions" and other searches with a few more words like "best practices" or "unchecked", etc., I see there is controversy over how to use exceptions. I used this solution in my code because the stream was performing a map that would take minutes. I wanted the user to be able to cancel the task so I checked at the beginning of each calculation for the flag "isUserCancelRequested" and threw an exception when true. It's clean, the exception code is isolated to small portion of the code, and it works.
Note that Stream.forEach does not provide the same strong guarantee about exceptions being relayed to the caller, so throwing an exception isn't guaranteed to work this way for Stream.forEach.
@Radiodef That is a valid point, thanks. The original post was about Iterable.forEach(), but I added your point to my text just for the completeness.
|
31

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

someObjects.allMatch(obj -> {
    return !some_condition_met;
});

1 Comment

I think this pretty much what I was looking for.
31

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);
    }
});

2 Comments

As from a previous answer, This requires Java 9 . The OP specifically asked about java 8
The .takeWhile call should be directly after .stream() so the stream stops directly after ongoing is set to false
13

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.

3 Comments

I'd suggest that actually using the Streams API and a functional approach here is preferable over creating this helper method if Java 8 is being used anyhow.
This is the classic takeWhile operation, and this question is but one of those demonstrating how much its lack in the Streams API is felt.
@Marko: takeWhile feels more like it would be an operation yielding items, not performing an action on each. Certainly in LINQ in .NET it would be poor form to use TakeWhile with an action with side-effects.
11

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));

2 Comments

Java 9 will offer support for takeWhile operation on streams.
Stream.takeWhile came to Android since SDK 34 (Android 14), so rxjava is still valuable on 2024. And, actually is Observable.fromCallable.
7

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.

Comments

7
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");
}

4 Comments

Above code using takeWhile method of java 9 and an extra variable to track the condition works perfectly fine for me.
The community encourages adding explanations alongisde code, rather than purely code-based answers (see here).
Hello and welcome to SO! While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value. Please read the tour, and How do I write a good answer?
maybe better test the condition directly in takeWhile without using ongoing
3

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;
    }

Comments

3

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>
});

1 Comment

The anyMatch will not stop the first call to peek. If you want to do something in the peek lamda only if "some_condition_met" is true, you will have to put an if statement in the peek lamda to do something only if "some_condition_met" is true.
1
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.

Comments

1

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/

Comments

1

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.

1 Comment

BTW if (some_condition_met) { return true; } return false; is just an inconvenient/unconventional way of writing return some_condition_met;
0

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.

3 Comments

Or AtomicBoolean?
This skips the object processing when !condition.ok(), however it doesn't prevent forEach() from looping over all the objects anyway. If the slow part is the forEach() iteration and not its consumer (eg, it gets objects from a slow network connection), then this approach isn't very useful.
Yes you are right, my answer is quite wrong in this case.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.