Groovy - how to exit each loop?
Solution 1
You cannot do it elegantly. You might see some people suggest throwing an Exception, but that's just plain ugly.
Here's some mailing list discussion on using each
vs. for
, and a couple people say that for
is preferred because of each
's inability to break from the iteration.
Your best bet is probably to change over to a for
loop and iterate:
for(def domain : records.children()) { // this may need some tweaking depending on types
// do stuff
if(condition) {
break;
}
}
Either that, or like you said, maybe use find or findAll to find the element you're looking for (the following code is paraphrased, I don't have time yet to test it out):
def result = records.children().find { domain -> domain.@domain_name == targetDomain }
result.children().each {
// print stuff
}
Related SO questions:
- best-pattern-for-simulating-continue-in-groovy-closure
- is-it-possible-to-break-out-of-closure-in-groovy
Solution 2
Replace each loop with any or find closure.
def list = [1, 2, 3, 4, 5]
list.any { element ->
if (element == 2)
return // continue
println element
if (element == 3)
true // break
}
Output
1
3
Solution 3
Regarding breaking out of the each loop see: is it possible to 'break' out of a groovy closure
Basically you have to throw and exception and catch it. The "break" keyword is only allowed inside loops not iterated "closures" (really code blocks).
You can use any complex code with "find" just make sure the function you call returns a Boolean. For example:
Boolean test(val) {
println "Testing $val"
return val == 1
}
def found = [3,4,5,1,6,3].find { test(it) }
println "Found $found"
Solution 4
I think this should work too, stopping at the first match.
def result = records.children().find { domain ->
if (domain.@domain_name == targetDomain) {
// Do stuff
...
return true
} else {
return false
}
}
Jack BeNimble
Updated on July 09, 2022Comments
-
Jack BeNimble almost 2 years
I'm new to Grails/Groovy and am trying to find a node in a an xml file; I've figured out how to iterate over all of them, but I want to exit the loop when the target node is found. I've read that instead of using "each", use "find", but the find examples I've seen are conditions. Right now the logic I have is going to iterate through the whole file without exiting. The code is below:
records.children().each {domain -> println "domain_name: " + domain.@domain_name if (domain.@domain_name == targetDomain) { println "target domain matched: " + domain.@domain_name domain.children().each {misc_field -> println "field_name: " + misc_field.@field_name println "field_type: " + misc_field.@field_type println "field_value: " + misc_field } } }
-
neonski over 14 yearsBut in the original problem by Jack, did he even need to break? It seems to me that the intent is to (in pseudo-groovy because i've never used it) records.children.find( @domain_name = targetDomain ).children().each (println)
-
Rob Hruska over 14 years@neonski - Yeah, I was just working on an edit to my answer with some code like you paraphrased. I think that's probably the more ideal solution.
-
Rob Hruska over 14 years@Jack - Can you clarify which one worked (for future readers' sake)? If it wasn't the
find
solution, you might try that too, just for the sake of experience. It's a bit more of a groovy-ish solution. -
Jack BeNimble over 14 yearsSure - I actually posted the answer before I had refreshed the comments. I used the first solution. I tried the second one, but the compiler says "unexpected token" at the "=" sign in this: @domain_name = targetDomain.
-
Rob Hruska over 14 years@Jack - Did you use
==
or=
? (Not that I'd expect using=
would throw an "unexpected token" error.) Also, usingdomain.'@domain_name'
might work, but again, not sure. -
alcoholiday almost 10 years+1 for using Find in this case. It's concise, and I find that using Find or FindAll is super handy, and makes the code easy to understand and test.
-
Alexander Stohr over 2 yearswhy is there a semicolon after the "break" keyword?