是否可以从Groovy break
.each{Closure}
,或者我应该使用经典循环?
答案 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
}
}
对我有用!