你能打破一个Groovy“每个”关闭?

时间:2010-06-15 23:25:41

标签: groovy

是否可以从Groovy break .each{Closure},或者我应该使用经典循环?

8 个答案:

答案 0 :(得分:181)

不,你不能在没有抛出异常的情况下中止“每个”。如果您希望在特定条件下中断,则可能需要经典循环。

或者,您可以使用“find”闭包而不是每个闭包,并在您休息时返回true。

此示例将在处理整个列表之前中止:

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
}

打印

1
2
3
4
5

但不打印6或7。

使用接受闭包的自定义中断行为编写自己的迭代器方法也非常容易:

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
}

同时打印:

1
2
3
4
5    

答案 1 :(得分:49)

每个循环替换为任何闭包。

def list = [1, 2, 3, 4, 5]
list.any { element ->
    if (element == 2)
        return // continue

    println element

    if (element == 3)
        return true // break
}

输出

1
3

答案 2 :(得分:10)

不,你不能在没有抛出异常的情况下从Groovy中的闭包中断。此外,您不应该使用控制流的异常。

如果你发现自己想要突破关闭,你应该首先考虑为什么要这样做,而不是如何做到这一点。首先要考虑的是用Groovy(概念)高阶函数之一替换有问题的闭包。以下示例:

for ( i in 1..10) { if (i < 5) println i; else return}

变为

(1..10).each{if (it < 5) println it}

变为

(1..10).findAll{it < 5}.each{println it} 

这也有助于澄清。它更好地说明了代码的意图。

所示示例中的潜在缺点是迭代仅在第一个示例中提前停止。如果您有性能方面的考虑因素,可能需要立即停止它。

但是,对于涉及迭代的大多数用例,您通常可以使用Groovy的find,grep,collect,inject等方法。他们通常采取一些“配置”,然后“知道”如何为您进行迭代,这样您就可以尽可能避免命令性循环。

答案 3 :(得分:2)

只需使用特殊关闭

// 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
}

答案 4 :(得分:0)

您不能从Groovy每个循环中中断,但是可以从Java“增强”的for循环中中断。

def a = [1, 2, 3, 4, 5, 6, 7]

for (def i : a) {
    if (i < 2)
        continue
    if (i > 5)
        break
    println i
}

输出:

2
3
4
5

这可能不一定适合所有情况,但对我有帮助:)

答案 5 :(得分:0)

我同意其他答案,不要使用异常来破坏每个。我也不喜欢创建一个额外的闭包 eachWithBreak,相反,我更喜欢一种现代方法:让我们使用 each 根据要求迭代集合,但细化集合以仅包含那些要迭代的元素,例如使用 findAll:

collection.findAll { !endCondition }.each { doSomething() }

例如,如果我们在 counter == 3 时中断什么我们可以编写此代码(已建议):

(0..5)
    .findAll { it < 3  }
    .each { println it }

这将输出

0
1
2

到目前为止一切顺利,但您会注意到一个小差异。我们的结束条件 counter == 3 的否定并不完全正确,因为 !(counter==3) 不等同于 it < 3。这是使代码工作所必需的,因为 findAll 实际上并没有中断循环而是一直持续到结束。

为了模拟真实情况,假设我们有以下代码:

for (n in 0..5) {
    if (n == 3)
        break
    println n
}

但是我们想使用each,所以让我们用一个函数来重写它来模拟中断条件:

def breakWhen(nr) { nr == 3 }
(0..5)
    .findAll { !breakWhen(it) }
    .each { println it }

输出:

0
1
2
4
5

现在您看到了 findAll 的问题。这不会停止,但会忽略不满足条件的元素。

为了解决这个问题,我们需要一个额外的变量来记住中断条件何时成立。此后,findAll 必须忽略所有剩余元素。

它应该是这样的:

def breakWhen(nr) { nr == 3 }
def loop = true
(0..5)
    .findAll {
        if (breakWhen(it))
            loop = false
        !breakWhen(it) && loop
    } .each {
        println it
    }

输出:

0
1
2

这就是我们想要的!

答案 6 :(得分:-4)

(1..10)。每个{

if(it&lt; 5)

println it

否则

返回false

答案 7 :(得分:-9)

你可以打破RETURN。例如

  def a = [1, 2, 3, 4, 5, 6, 7]
  def ret = 0
  a.each {def n ->
    if (n > 5) {
      ret = n
      return ret
    }
  }

对我有用!