Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best pattern for simulating "continue" in Groovy closure

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...     } } 
like image 493
talanb Avatar asked Oct 15 '08 17:10

talanb


People also ask

How do you continue Groovy?

Groovy - Continue Statement The continue statement complements the break statement. Its use is restricted to while and for loops. When a continue statement is executed, control is immediately passed to the test condition of the nearest enclosing loop to determine whether the loop should continue.

How closure works in Groovy?

A closure in Groovy is an open, anonymous, block of code that can take arguments, return a value and be assigned to a variable. A closure may reference variables declared in its surrounding scope.

How do you break Groovy on each loop?

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.

How do I create a closure in Groovy?

A closure is an anonymous block of code. In Groovy, it is an instance of the Closure class. Closures can take 0 or more parameters and always return a value. Additionally, a closure may access surrounding variables outside its scope and use them — along with its local variables — during execution.


1 Answers

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.

like image 89
shemnon Avatar answered Sep 30 '22 18:09

shemnon