Tapas Bose
Tapas Bose

Reputation: 29806

Break or return from Java 8 stream forEach?

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

Answers (15)

user_3380739
user_3380739

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

Sam Deir
Sam Deir

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

Abhishek Jaipurkar
Abhishek Jaipurkar

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

Sahil
Sahil

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

Khairul Bashar Lemon
Khairul Bashar Lemon

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

Thomas Decaux
Thomas Decaux

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

Honza Zidek
Honza Zidek

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

tuga
tuga

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

avijendr
avijendr

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

Jesper
Jesper

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

Julian Pieles
Julian Pieles

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

Mohammad Adnan
Mohammad Adnan

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

frhack
frhack

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

Kanagavelu Sugumar
Kanagavelu Sugumar

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

Jon Skeet
Jon Skeet

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

Related Questions