Is it possible to break
from a Groovy .each{Closure}
, or should I be using a classic loop instead?
8 Answers
Nope, you can't abort an "each" without throwing an exception. You likely want a classic loop if you want the break to abort under a particular condition.
Alternatively, you could use a "find" closure instead of an each and return true when you would have done a break.
This example will abort before processing the whole list:
def a = [1, 2, 3, 4, 5, 6, 7]
a.find {
if (it > 5) return true // break
println it // do the stuff that you wanted to before break
return false // keep looping
}
Prints
1
2
3
4
5
but doesn't print 6 or 7.
It's also really easy to write your own iterator methods with custom break behavior that accept closures:
List.metaClass.eachUntilGreaterThanFive = { closure ->
for ( value in delegate ) {
if ( value > 5 ) break
closure(value)
}
}
def a = [1, 2, 3, 4, 5, 6, 7]
a.eachUntilGreaterThanFive {
println it
}
Also prints:
1
2
3
4
5

- 26,511
- 10
- 70
- 81
-
4I've also submitted a patch to groovy that adds a findResult method that does a short-circuited find that returns the first non-null result from the closure. This method could be used to cover almost all situations that someone might want to break out of an each early. Check the patch to see if it gets accepted and rolled into groovy (I'm hoping by 1.8): http://jira.codehaus.org/browse/GROOVY-4253 – Ted Naleid Jun 23 '10 at 03:07
-
2I've tried this case : def a = [1, 2, 3, 4, 5, 6, 7, -1, -2] It returned 1 2 3 4 5 -1 -2 . So, "breaK" does not work. – Phat H. VU Dec 06 '13 at 08:12
-
Correct find is correct option, each will never break by return – Pushkar Jul 16 '15 at 07:45
-
is `find` better than `any` - see the other answer below from @Michal that one works for me – Rhubarb Mar 10 '17 at 11:48
-
Ted Naleid's patch to groovy is very useful. Use findResult instead if you actually need the result from the find operation and not the element itself. Ex: `def test = [2] test.findResult{ it * 2 }` will return 4 instead of 2 – Doug Jul 03 '17 at 15:28
Replace each loop with any closure.
def list = [1, 2, 3, 4, 5]
list.any { element ->
if (element == 2)
return // continue
println element
if (element == 3)
return true // break
}
Output
1
3

- 5,381
- 3
- 43
- 39
-
Just a trick. What happens if there is a statement after "break". This statement will be still exectured after meet "break". – Phat H. VU Dec 07 '13 at 05:54
-
2@Phat H. VU I've added return. The statement after "break" won't be executed – Michal Zmuda Dec 07 '13 at 17:13
-
2Thanks for your reply. You're right. I also vote up your answer. More : the any method is defined in DefaultGroovyMethods and it is a predicate function that returns true if an element in a collection satisfies the supplied predicate closure. – Phat H. VU Dec 09 '13 at 01:57
-
Using `any()` in this way is a bit misleading, but it certainly does work and gives you the ability to _break_ or _continue_. – vegemite4me May 15 '14 at 16:52
-
1like @vegemite4me, I think this is a "trick" but you don't understand well the meaning of any. For maintenability, you should not use this solution. – MatRt Jul 01 '15 at 11:55
No, you can't break from a closure in Groovy without throwing an exception. Also, you shouldn't use exceptions for control flow.
If you find yourself wanting to break out of a closure you should probably first think about why you want to do this and not how to do it. The first thing to consider could be the substitution of the closure in question with one of Groovy's (conceptual) higher order functions. The following example:
for ( i in 1..10) { if (i < 5) println i; else return}
becomes
(1..10).each{if (it < 5) println it}
becomes
(1..10).findAll{it < 5}.each{println it}
which also helps clarity. It states the intent of your code much better.
The potential drawback in the shown examples is that iteration only stops early in the first example. If you have performance considerations you might want to stop it right then and there.
However, for most use cases that involve iterations you can usually resort to one of Groovy's find, grep, collect, inject, etc. methods. They usually take some "configuration" and then "know" how to do the iteration for you, so that you can actually avoid imperative looping wherever possible.

- 22,214
- 7
- 47
- 42
-
1"No, you can't break from a closure in Groovy without throwing an exception.".This is what Scala does, see http://dev.bizo.com/2010/01/scala-supports-non-local-returns.html – OlliP Oct 07 '16 at 12:15
Just using special Closure
// declare and implement:
def eachWithBreak = { list, Closure c ->
boolean bBreak = false
list.each() { it ->
if (bBreak) return
bBreak = c(it)
}
}
def list = [1,2,3,4,5,6]
eachWithBreak list, { it ->
if (it > 3) return true // break 'eachWithBreak'
println it
return false // next it
}

- 317
- 2
- 5
-
3and if you have 1 billion rows and the inner closure returns true on the first call, then you will iterate over 1 billion minus one values. :( – sbglasius Oct 26 '16 at 18:24
You can't break from a Groovy each loop, but you can break from a java "enhanced" for loop.
def a = [1, 2, 3, 4, 5, 6, 7]
for (def i : a) {
if (i < 2)
continue
if (i > 5)
break
println i
}
Output:
2
3
4
5
This might not fit for absolutely every situation but it's helped for me :)

- 471
- 4
- 11
I agree with other answers not to use an exception to break an each. I also do not prefer to create an extra closure eachWithBreak
, instead of this I prefer a modern approach: let's use the each
to iterate over the collection, as requested, but refine the collection to contain only those elements to be iterated, for example with findAll
:
collection.findAll { !endCondition }.each { doSomething() }
For example, if we what to break when the counter == 3
we can write this code (already suggested):
(0..5)
.findAll { it < 3 }
.each { println it }
This will output
0
1
2
So far so good, but you will notice a small discrepancy though. Our end condition, negation of counter == 3
is not quite correct because !(counter==3)
is not equivalent with it < 3
. This is necessary to make the code work since findAll
does not actually break the loop but continues until the end.
To emulate a real situation, let's say we have this code:
for (n in 0..5) {
if (n == 3)
break
println n
}
but we want to use each
, so let's rewrite it using a function to simulate a break condition:
def breakWhen(nr) { nr == 3 }
(0..5)
.findAll { !breakWhen(it) }
.each { println it }
with the output:
0
1
2
4
5
now you see the problem with findAll
. This does not stop, but ignores that element where the condition is not met.
To solve this issues, we need an extra variable to remember when the breaking condition become true. After this moment, findAll
must ignore all remaining elements.
This is how it should look like:
def breakWhen(nr) { nr == 3 }
def loop = true
(0..5)
.findAll {
if (breakWhen(it))
loop = false
!breakWhen(it) && loop
} .each {
println it
}
with the output:
0
1
2
That's what we want!

- 366
- 2
- 8
(1..10).each{
if (it < 5)
println it
else
return false

- 315
- 3
- 8
-
2This does not break out of the `each`, it simply does not print values larger than 4. The `else` is superfluous, your code would do the same without it. Also, you can prove `each` doesn't break with `return false` if you put `println "not breaking"` just after `else` and just before `return false`. – Stefan van den Akker May 26 '17 at 10:23
-
Please do at least minimum effort to format your code for readability. There is a visual preview when you reply and lot's of instruction how to do it – Mateusz Was Oct 27 '17 at 16:33
You could break by RETURN
. For example
def a = [1, 2, 3, 4, 5, 6, 7]
def ret = 0
a.each {def n ->
if (n > 5) {
ret = n
return ret
}
}
It works for me!

- 1
- 1
-
7Which is exactly what the OP asked, even though it's obviously not what he meant. – Szocske Aug 26 '13 at 18:54
-
Can I have a description why this has negative votes. This seems to me the same concept as what the top answer says (with less explanation) with +133 votes. – Skepi Jan 16 '17 at 12:52
-
2@Skepi You cannot "break" above closure. You can break `any` method of the array by returning `false`. You cannot break `each` method in the same way. – Nux Jan 16 '17 at 15:17