[英]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.