Can you break from a Groovy “each” closure?

后端 未结 6 1089
不思量自难忘°
不思量自难忘° 2020-11-27 13:17

Is it possible to break from a Groovy .each{Closure}, or should I be using a classic loop instead?

相关标签:
6条回答
  • 2020-11-27 13:33

    (1..10).each{

    if (it < 5)

    println it

    else

    return false

    0 讨论(0)
  • 2020-11-27 13:43

    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    
    
    0 讨论(0)
  • 2020-11-27 13:44

    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
    }
    
    0 讨论(0)
  • 2020-11-27 13:49

    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!

    0 讨论(0)
  • 2020-11-27 13:51

    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.

    0 讨论(0)
  • 2020-11-27 13:56

    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
    
    0 讨论(0)
提交回复
热议问题