在Groovy闭包中模拟“继续”的最佳模式

Groovy似乎并不支持中断,而是从closures中继续。 什么是模拟这个最好的方法?

revs.eachLine { line -> if (line ==~ /-{28}/) { // continue to next line... } } 

你只能支持继续干净,不能中断。 特别是像每个线和每个东西。 无法支持中断与如何评估这些方法有关,没有考虑未完成可以传递给方法的循环。 以下是如何支持继续 –

最好的办法(假设你不需要结果值)。

 revs.eachLine { line -> if (line ==~ /-{28}/) { return // returns from the closure } } 

如果你的样品真的很简单,这是可读性好。

 revs.eachLine { line -> if (!(line ==~ /-{28}/)) { // do what you would normally do } } 

另一种select是模拟继续通常在字节码级别执行的操作。

 revs.eachLine { line -> while (true) { if (line ==~ /-{28}/) { break } // rest of normal code break } } 

一个可能的方式来支持rest是通过例外:

 try { revs.eachLine { line -> if (line ==~ /-{28}/) { throw new Exception("Break") } } } catch (Exception e) { } // just drop the exception 

您可能希望使用自定义的exceptiontypes来避免掩盖其他真正的exception,特别是如果您在该类中进行其他处理,可能会抛出真正的exception,如NumberFormatExceptions或IOExceptions。

闭包不能中断或继续,因为它们不是循环/迭代结构。 相反,它们是用于处理/解释/处理迭代逻辑的工具。 您可以忽略给定的迭代,只需从闭包中返回而不进行处理,如下所示:

 revs.eachLine { line -> if (line ==~ /-{28}/) { return } } 

中断支持不会发生在closures级别,而是由方法调用的语义暗示接受closures。 简而言之,这意味着不是调用“每个”像某个集合的意图处理整个集合的东西,你应该调用find来处理,直到满足某个条件。 大多数(所有?)次你觉得需要打破封闭你真正想要做的是在你的迭代中find一个特定的条件,这使得find方法不仅符合你的逻辑需求,而且符合你的意图。 可悲的是,一些API不支持find方法…例如文件。 花在争论语言上的所有时间都应该包括rest/继续,可能已经很好地将search方法添加到这些被忽视的区域。 像firstDirMatching(Closure c)或findLineMatching(Closure c)会有很长的路要走,回答“为什么我不能从…中断? 在邮件列表中popup的问题。 也就是说,通过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}/ } 

其他涉及exception和其他魔法的黑客行为可能会起作用,但是会在某些情况下引入额外开销,并在其他情况下使可读性变得复杂 真正的答案是看你的代码,并问你是否真的迭代或search。

如果您在Java中预先创build一个静态的Exception对象,然后从闭包中引发(静态)exception,那么运行时成本是最小的。 真正的成本是创造例外,而不是抛出。 根据Scala的发明者Martin Odersky的说法,许多JVM实际上可以优化抛出指令来跳转。

这可以用来模拟一个中断:

 final static BREAK = new Exception(); //... try { ... { throw BREAK; } } catch (Exception ex) { /* ignored */ } 

使用return继续任何closures都会中断

文件内容:

 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,你可以将一个迭代器转换为一个可观察的元素。

然后你可以用一个filter代替继续 ,并用takeWhile来中断

这里是一个例子:

 import rx.Observable Observable.from(1..100000000000000000) .filter { it % 2 != 1} .takeWhile { it<10 } .forEach {println it}