似乎 Groovy 不支持break
和continue
from 闭包。模拟这种情况的最佳方法是什么?
revs.eachLine { line ->
if (line ==~ /-{28}/) {
// continue to next line...
}
}
你只能支持干净地继续,不能打破。尤其是像 eachLine 和 each 这样的东西。无法支持中断与如何评估这些方法有关,没有考虑没有完成可以传达给方法的循环。以下是如何支持继续 -
最佳方法(假设您不需要结果值)。
revs.eachLine { line ->
if (line ==~ /-{28}/) {
return // returns from the closure
}
}
如果您的示例真的那么简单,那么这对可读性很有好处。
revs.eachLine { line ->
if (!(line ==~ /-{28}/)) {
// do what you would normally do
}
}
另一种选择,模拟 continue 通常在字节码级别执行的操作。
revs.eachLine { line ->
while (true) {
if (line ==~ /-{28}/) {
break
}
// rest of normal code
break
}
}
支持中断的一种可能方法是通过异常:
try {
revs.eachLine { line ->
if (line ==~ /-{28}/) {
throw new Exception("Break")
}
}
} catch (Exception e) { } // just drop the exception
您可能希望使用自定义异常类型来避免屏蔽其他真正的异常,尤其是当您在该类中进行其他可能引发真正异常的处理时,例如 NumberFormatExceptions 或 IOExceptions。
闭包不能中断或继续,因为它们不是循环/迭代构造。相反,它们是用于处理/解释/处理迭代逻辑的工具。您可以通过简单地从闭包返回而不进行处理来忽略给定的迭代,如下所示:
revs.eachLine { line ->
if (line ==~ /-{28}/) {
return
}
}
中断支持不会发生在闭包级别,而是由接受闭包的方法调用的语义所暗示。简而言之,这意味着不要在诸如旨在处理整个集合的集合之类的东西上调用“每个”,而应该调用 find 它将一直处理直到满足特定条件。大多数(全部?)时间你觉得需要打破闭包,你真正想做的是在你的迭代中找到一个特定的条件,这使得 find 方法不仅符合你的逻辑需求,而且符合你的意图。遗憾的是,一些 API 缺乏对 find 方法的支持……例如 File。可能所有花费在争论语言是否应该包括中断/继续的时间都可以很好地用于将 find 方法添加到这些被忽视的区域。像 firstDirMatching(Closure c) 或 findLineMatching(Closure c) 这样的东西会走很长的路,回答 99+% 的“为什么我不能摆脱......?” 邮件列表中弹出的问题。也就是说,通过 MetaClass 或 Categories 自己添加这些方法很简单。
class FileSupport {
public static String findLineMatching(File f, Closure c) {
f.withInputStream {
def r = new BufferedReader(new InputStreamReader(it))
for(def l = r.readLine(); null!=l; l = r.readLine())
if(c.call(l)) return l
return null
}
}
}
using(FileSupport) { new File("/home/me/some.txt").findLineMatching { line ==~ /-{28}/ }
其他涉及异常和其他魔法的 hack 可能会起作用,但在某些情况下会引入额外的开销,并在其他情况下会混淆可读性。真正的答案是查看您的代码并询问您是否真正在迭代或搜索。
如果您在 Java 中预先创建一个静态 Exception 对象,然后从闭包内抛出(静态)异常,则运行时成本是最小的。真正的成本是在创建异常时产生的,而不是在抛出它时。根据 Martin Odersky(Scala 的发明者)的说法,许多 JVM 实际上可以将 throw 指令优化为单次跳转。
这可以用来模拟休息:
final static BREAK = new Exception();
//...
try {
... { throw BREAK; }
} catch (Exception ex) { /* ignored */ }
使用return继续,使用任何关闭break。
例子
文件内容:
1
2
----------------------------
3
4
5
Groovy 代码:
new FileReader('myfile.txt').any { line ->
if (line =~ /-+/)
return // continue
println line
if (line == "3")
true // break
}
输出:
1
2
3
在这种情况下,您可能应该考虑该find()
方法。它在第一次传递给它的闭包返回 true 后停止。
使用rx-java,您可以将一个可迭代对象转换为可观察对象。
然后你可以用过滤器替换continue并用takeWhile中断
这是一个例子:
import rx.Observable
Observable.from(1..100000000000000000)
.filter { it % 2 != 1}
.takeWhile { it<10 }
.forEach {println it}