0

I have the following simple groovy script that I understand will not work after reading here. But my question now is why does this not exit the closure. Could someone provide an explanation or point my to the docs that discuss closures.Thanks

def inputFile = new File("input.txt")
inputFile.eachLine{ it ,i ->
  if(it.contains("abcd")){
    println "abcd found on line: " + i
    return true
  }
}
Community
  • 1
  • 1
KBusc
  • 663
  • 8
  • 24
  • Here's a very good explanation: http://stackoverflow.com/questions/3049790/break-from-groovy-each-closure – Opal Oct 23 '14 at 12:57
  • Yea I just read this actually, I am going to edit my question now. I would still like to know why this is the case – KBusc Oct 23 '14 at 12:59

2 Answers2

3

The basic pseudo code ran in eachLine is:

while (true) {
    def line = readLineFromFile()
    if (line==null) {
        break
    }
    closure(line, count++)
}

So there is nothing else, than the end of the file, to stop. Your return in the closure works, but it returns just from the closure.

For details see the source of org.codehaus.groovy.runtime.IOGroovyMethods.eachLine.

Closures are not language constructs like while or for. They are just passed in anonymous functions with context. It gets more clear, if you write it out, what the code actually means (no groovy shortcuts): inputFile.eachLine({it,i->...}) (note the () from the method call here)

In general: each.* in groovy does not care for the result of your closure. A return in the closure just means an early bail out (in your case it's a no-op).

So for the general question, can you break from closures? "No". Iff your caller works with the result, state, ... of the closure in any way to allow you to break from it (e.g. [].find() does: iterate the list, until the closure returns true, then return the element), you are not able to (well you can throw an exception).

cfrick
  • 35,203
  • 6
  • 56
  • 68
1

Groovy's each* methods do NOT exit the loop if you do return in it's "body". they simply cancel the execution of this body instance and move on to the next one.

In contrast, "find" method DOES return immediately if the closure returns true.

You can either use the plain looping with for or while, or (not recommended) let your closure throw some exception

injecteer
  • 20,038
  • 4
  • 45
  • 89