簡體   English   中英

如何從 groovy 關閉返回並停止執行?

[英]How does one return from a groovy closure and stop its execution?

我想從閉包返回,就像在循環中使用 break 語句一樣。

例如:

largeListOfElements.each{ element->
    if(element == specificElement){
        // do some work          
        return // but this will only leave this iteration and start the next 
    }
}

在上面的 if 語句中,我想停止遍歷列表並保留閉包以避免不必要的迭代。

我見過一個解決方案,其中在閉包內拋出異常並在外部捕獲異常,但我不太喜歡該解決方案。

除了更改代碼以避免這種算法之外,是否有任何解決方案?

我認為您想使用 find 而不是 each (至少對於指定的示例)。 閉包不直接支持中斷。

在幕后,groovy 實際上並不使用閉包進行查找,而是使用 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"

我認為您在錯誤的抽象級別上工作。 .each塊完全按照它說的做:它為每個元素執行一次閉包。 你可能想要的是使用List.indexOf來找到正確的specificElement ,然后做你需要做的工作。

如果您想處理所有元素直到找到特定元素,您還可以執行以下操作:

largeListOfElements.find { element ->
    // do some work
    element == specificElement
}

盡管您可以將其與任何類型的“中斷條件”一起使用。 我只是用它通過返回來處理集合的前 n 個元素

counter++ >= n

在關閉結束時。

在 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,縮短此類循環的方法是拋出用戶定義的異常。 我不知道語法是什么(不是一個 groovy 程序員),但是 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"; }     

今天,我在處理每個閉包時都遇到了類似的問題。 我想根據我的情況打破執行流程,但無法做到。

如果您希望基於某些條件返回布爾值,那么在 groovy 中最簡單的方法是在列表上使用any()而不是每個。

好的 ole for循環仍然適用於您的用例的 Groovy

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM