Using return; will work just fine. It will not prevent the full loop from completing. It will only stop executing the current iteration of the forEach loop.
Try the following little program:
public static void main(String[] args) {
ArrayList<String> stringList = new ArrayList<>();
stringList.add("a");
stringList.add("b");
stringList.add("c");
stringList.stream().forEach(str -> {
if (str.equals("b")) return; // only skips this iteration.
System.out.println(str);
});
}
Output:
a
c
Notice how the return; is executed for the b iteration, but c prints on the following iteration just fine.
Why does this work?
The reason the behavior seems unintuitive at first is because we are used to the return statement interrupting the execution of the whole method. So in this case, we expect the main method execution as a whole to be halted.
However, what needs to be understood is that a lambda expression, such as:
str -> {
if (str.equals("b")) return;
System.out.println(str);
}
... really needs to be considered as its own distinct "method", completely separate from the main method, despite it being conveniently located within it. So really, the return statement only halts the execution of the lambda expression.
The second thing that needs to be understood is that:
stringList.stream().forEach()
... is really just a normal loop under the covers that executes the lambda expression for every iteration.
With these 2 points in mind, the above code can be rewritten in the following equivalent way (for educational purposes only):
public static void main(String[] args) {
ArrayList<String> stringList = new ArrayList<>();
stringList.add("a");
stringList.add("b");
stringList.add("c");
for(String s : stringList) {
lambdaExpressionEquivalent(s);
}
}
private static void lambdaExpressionEquivalent(String str) {
if (str.equals("b")) {
return;
}
System.out.println(str);
}
With this "less magic" code equivalent, the scope of the return statement becomes more apparent.
Using return; will work just fine. It will not prevent the full loop from completing. It will only stop executing the current iteration of the forEach loop.
Try the following little program:
public static void main(String[] args) {
ArrayList<String> stringList = new ArrayList<>();
stringList.add("a");
stringList.add("b");
stringList.add("c");
stringList.stream().forEach(str -> {
if (str.equals("b")) return; // only skips this iteration.
System.out.println(str);
});
}
Output:
a
c
Notice how the return; is executed for the b iteration, but c prints on the following iteration just fine.
Why does this work?
The reason the behavior seems unintuitive at first is because we are used to the return statement interrupting the execution of the whole method. So in this case, we expect the main method execution as a whole to be halted.
However, what needs to be understood is that a lambda expression, such as:
str -> {
if (str.equals("b")) return;
System.out.println(str);
}
... really needs to be considered as its own distinct "method", completely separate from the main method, despite it being conveniently located within it. So really, the return statement only halts the execution of the lambda expression.
The second thing that needs to be understood is that:
stringList.stream().forEach()
... is really just a normal loop under the covers that executes the lambda expression for every iteration.
With these 2 points in mind, the above code can be rewritten in the following equivalent way (for educational purposes only):
public static void main(String[] args) {
ArrayList<String> stringList = new ArrayList<>();
stringList.add("a");
stringList.add("b");
stringList.add("c");
for(String s : stringList) {
lambdaExpressionEquivalent(s);
}
}
private static void lambdaExpressionEquivalent(String str) {
if (str.equals("b")) {
return;
}
System.out.println(str);
}
With this "less magic" code equivalent, the scope of the return statement becomes more apparent.
Another solution: go through a filter with your inverted conditions : Example :
if(subscribtion.isOnce() && subscribtion.isCalled()){
continue;
}
can be replaced with
.filter(s -> !(s.isOnce() && s.isCalled()))
The most straightforward approach seem to be using "return;" though.
I like using the continue and break statements in my for each loops in Java. My CTO, doesn't like them, and suggests that "used outside of a switch statement, it gives you multiple return points from a block of code, and it – gives you GOTO like functionality". Are there any suggestions of arguing points that I can make, to defend this position... or is he right?
java - How to put continue in side forEach loop in java8 - Stack Overflow
Break or return from Java 8 stream forEach? - Stack Overflow
How to do it in Java 8 stream api foreach continue or break - Stack Overflow
What does 'return' do inside a forEach loop? (or for any kind of loop, are there differences in behaviour?)
You can use return. It won't stop the whole loop, instead, it will just stop the current iteration.
Use it like this:
List<Integer> numList = Arrays.asList(10,21,31,40,59,60);
numList.forEach( x-> {
if( x%2 == 0) {
return; // only skips this iteration.
}
System.out.println(x);
});
I think in this case, the best solution is filter the list before execute the println...
exemple (I didn't test):
List<Integer> numList = Arrays.asList(10,21,31,40,59,60);
numList.stream().filter(x-> x%2 != 0).forEach(System.out::println);
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);
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;
}
})