如何从groovy闭包返回并停止其执行?

如何从groovy闭包返回并停止其执行?,groovy,closures,return,Groovy,Closures,Return,我想从闭包返回,就像在循环中使用break语句一样 例如: largeListOfElements.each{ element-> if(element == specificElement){ // do some work return // but this will only leave this iteration and start the next } } 在上面的if语句中,我希望停止遍历列表,并保留闭

我想从闭包返回,就像在循环中使用break语句一样

例如:

largeListOfElements.each{ element->
    if(element == specificElement){
        // do some work          
        return // but this will only leave this iteration and start the next 
    }
}
在上面的if语句中,我希望停止遍历列表,并保留闭包以避免不必要的迭代

我见过一种在闭包内抛出异常并在闭包外捕获异常的解决方案,但我不太喜欢这种解决方案


除了更改代码以避免这种算法之外,还有其他解决方案吗

我认为你在错误的抽象层次上工作。
。每个
块完全按照它所说的做:它对每个元素执行一次闭包。您可能希望使用
List.indexOf
来查找正确的
specific元素
,然后对其执行所需的工作。

我认为您希望使用find而不是每个元素(至少对于指定的示例而言)。闭包不直接支持break

实际上,groovy也没有为find使用闭包,而是使用for循环

或者,您可以编写自己的增强版本的find/each迭代器,该迭代器接受一个条件测试闭包,如果找到匹配项,则调用另一个闭包,如果满足匹配项,则中断该闭包

下面是一个例子:

Object.metaClass.eachBreak = { ifClosure, workClosure -> for (Iterator iter = delegate.iterator(); iter.hasNext();) { def value = iter.next() if (ifClosure.call(value)) { workClosure.call(value) break } } } def a = ["foo", "bar", "baz", "qux"] a.eachBreak( { it.startsWith("b") } ) { println "working on $it" } // prints "working on bar" Object.metaClass.eachBreak={ifClosure,workClosure-> for(迭代器iter=delegate.Iterator();iter.hasNext();){ def值=iter.next() if(ifClosure.call(值)){ workClosure.call(值) 打破 } } } DEFA=[“foo”、“bar”、“baz”、“qux”] a、 eachBreak({it.startsWith(“b”)}){ println“处理$it” } //打印“在酒吧工作”
如果要处理所有元素直到找到特定元素,还可以执行以下操作:

largeListOfElements.find { element ->
    // do some work
    element == specificElement
}
尽管您可以将其用于任何类型的“中断条件”。 我只是使用它通过返回来处理集合的前n个元素

counter++ >= n

在闭包结束时。

我理解groovy,缩短这类循环的方法是抛出一个用户定义的异常。我不知道语法会是什么(不是grrovy程序员),但是groovy在JVM上运行,所以它会像:

class ThisOne extends Exception {Object foo; ThisOne(Object foo) {this.foo=foo;}}

try { x.each{ if(it.isOk()) throw new ThisOne(it); false} }
catch(ThisOne x) { print x.foo + " is ok"; }     

在paulmurray给出答案后,我自己也不确定如果在闭包中抛出异常会发生什么,因此我设计了一个JUnit测试用例,很容易思考:

class TestCaseForThrowingExceptionFromInsideClosure {

    @Test
    void testEearlyReturnViaException() {
        try {
            [ 'a', 'b', 'c', 'd' ].each {                 
                System.out.println(it)
                if (it == 'c') {
                    throw new Exception("Found c")
                } 
            }
        }
        catch (Exception exe) {
            System.out.println(exe.message)
        }
    }
}  
上面的输出是:

a
b
c
Found c
但请记住,“不应将异常用于流控制”,请特别参阅此堆栈溢出问题:

因此,上述解决方案在任何情况下都不太理想。只需使用:

class TestCaseForThrowingExceptionFromInsideClosure {

    @Test
    void testEarlyReturnViaFind() {
        def curSolution
        [ 'a', 'b', 'c', 'd' ].find {                 
            System.out.println(it)
            curSolution = it
            return (it == 'c') // if true is returned, find() stops
        }
        System.out.println("Found ${curSolution}")
    }
}  
上面的输出也是:

a
b
c
Found c

今天,我在处理每次关闭时都遇到了类似的问题。我想根据自己的情况打破执行流程,但做不到


在groovy中最简单的方法是,如果您希望根据某些条件返回布尔值,则在列表中使用any()而不是每个。

Good ole
for
循环在groovy中仍然适用于您的用例

for (element in largeListOfElements) {
    if(element == specificElement){
        // do some work          
        return
    }
}

OP对他想要的东西有点含糊不清:“在上面的if语句中,我希望停止遍历列表,留下闭包以避免不必要的迭代。”但我强烈怀疑你是对的!不仅如此,对于感兴趣的元素之前的元素,没有“做一些工作”注释。