【发布时间】:2015-01-17 10:05:23
【问题描述】:
我在 Java 中看到的
Java 8 允许对链式函数进行惰性求值以避免性能损失。
例如,我可以有一个值列表并像这样处理它:
someList.stream()
.filter( v -> v > 0)
.map( v -> v * 4)
.filter( v -> v < 100)
.findFirst();
我将许多闭包传递给在流上调用的方法以处理集合中的值,然后只获取第一个。
这看起来好像代码必须遍历整个集合,过滤它,然后遍历整个结果并应用一些逻辑,然后再次过滤整个结果,最后只抓取一个元素。
实际上,编译器以更智能的方式处理此问题并优化所需的迭代次数。
这是可能的,因为在调用findFirst 之前不会进行任何实际处理。这样编译器就知道我想要实现什么,它可以找出如何以一种有效的方式来实现它。
查看video of a presentation by Venkat Subramaniam 以获得更详细的说明。
我想在 Groovy 中做什么
在回答question about Groovy here on StackOverflow 时,我想出了一种方法来执行 OP 试图以更易读的方式完成的任务。我没有建议它,因为这意味着性能下降。
示例如下:
collectionOfSomeStrings.inject([]) { list, conf -> if (conf.contains('homepage')) { list } else { list << conf.trim() } }
在语义上,这可以重写为
collectionOfSomeStrings.grep{ !it.contains('homepage')}.collect{ it.trim() }
我发现它更容易理解,但可读性是有代价的。此代码需要原始集合的传递和grep 的结果的另一次迭代。这不太理想。
它看起来不像 GDK 的 grep、collect 和 findAll 方法像 Java 8 的流 API 中的方法那样被延迟评估。有没有办法让他们表现得像这样?我可以使用 Groovy 中的任何替代库吗?
我想有可能在 Groovy 中以某种方式使用 Java 8 并具有此功能。我欢迎对细节进行解释,但理想情况下,我希望能够使用旧版本的 Java 来做到这一点。
我找到了way to combine closures,但这并不是我真正想做的。我不仅想链接闭包本身,还想链接我传递给它们的函数。
谷歌搜索 Groovy 和 Streams 主要产生与 I/O 相关的结果。通过搜索惰性求值、函数式和 Groovy,我没有找到任何感兴趣的东西。
【问题讨论】:
-
groovy 2.3 支持 jdk8 groovy.codehaus.org/Groovy+2.3+release+notes。您的示例使用 groovy 闭包可以正常工作:
[-1,1,2,3,4].stream().filter{it>0}.map{it*4}.filter{it < 100}.findFirst().get() -
@cfrick 我可以使用早期版本的 JDK 获得这样的结果吗?
-
没有。这实际上使用了 JDK8 API,但可以使用闭包代替 lambdas
-
当然,让我们看看其他人怎么说。也许像 rxgroovy 这样的东西可以为你工作?
标签: groovy functional-programming closures java-8 lazy-evaluation