Best pattern for simulating "continue" in Groovy closure

talanb picture talanb · Oct 15, 2008 · Viewed 43k times · Source

It seems that Groovy does not support break and continue from within a closure. What is the best way to simulate this?

revs.eachLine { line -> 
    if (line ==~ /-{28}/) {
         // continue to next line...
    }
}

Answer

shemnon picture shemnon · Oct 15, 2008

You can only support continue cleanly, not break. Especially with stuff like eachLine and each. The inability to support break has to do with how those methods are evaluated, there is no consideration taken for not finishing the loop that can be communicated to the method. Here's how to support continue --

Best approach (assuming you don't need the resulting value).

revs.eachLine { line -> 
    if (line ==~ /-{28}/) {
        return // returns from the closure
    }
}

If your sample really is that simple, this is good for readability.

revs.eachLine { line -> 
    if (!(line ==~ /-{28}/)) {
        // do what you would normally do
    }
}

another option, simulates what a continue would normally do at a bytecode level.

revs.eachLine { line -> 
    while (true) {
        if (line ==~ /-{28}/) {
            break
        }
        // rest of normal code
        break
    }

}

One possible way to support break is via exceptions:

try {
    revs.eachLine { line -> 
        if (line ==~ /-{28}/) {
            throw new Exception("Break")
        }
    }
} catch (Exception e) { } // just drop the exception

You may want to use a custom exception type to avoid masking other real exceptions, especially if you have other processing going on in that class that could throw real exceptions, like NumberFormatExceptions or IOExceptions.