Java 8 流:多个过滤器与复杂条件

2022-08-31 05:05:21

有时,您希望筛选具有多个条件的 :Stream

myList.stream().filter(x -> x.size() > 10).filter(x -> x.isCool()) ...

或者你可以对一个复杂的条件和一个单一的:filter

myList.stream().filter(x -> x.size() > 10 && x -> x.isCool()) ...

我的猜测是第二种方法具有更好的性能特征,但我不知道

第一种方法在可读性方面获胜,但什么对性能更好?


答案 1

必须为两个备选项执行的代码非常相似,以至于您无法可靠地预测结果。底层对象结构可能有所不同,但这对热点优化器来说不是一个挑战。因此,这取决于其他周围的条件,如果有任何差异,这些条件将产生更快的执行速度。

组合两个筛选器实例会创建更多的对象,从而创建更多的委派代码,但是如果您使用方法引用而不是 lambda 表达式(例如,替换为 ),则这种情况可能会更改。这样,您就消除了为 lambda 表达式创建的合成委派方法。因此,使用两个方法引用组合两个筛选器可能会创建与使用 lambda 表达式的单个调用相同或更少的委派代码。filter(x -> x.isCool())filter(ItemType::isCool)filter&&

但是,如前所述,这种开销将被HotSpot优化器消除,并且可以忽略不计。

从理论上讲,两个滤波器可能比单个滤波器更容易并行化,但这只与计算密集型任务相关¹。

所以没有简单的答案。

底线是,不要考虑低于气味检测阈值的这种性能差异。使用更具可读性的内容。


¹...并且需要对后续阶段进行并行处理的实现,这是标准流实现目前未走过的道路


答案 2

从性能角度来看,复杂的过滤条件更好,但最佳性能将显示老式的循环,因为具有标准的循环是最佳选择。小数组上10个元素的差异可能约为2倍,对于大数组的差异并不大。
你可以看看我的GitHub项目,在那里我对多个数组迭代选项进行了性能测试。if clause

对于小型阵列 10 元素吞吐量 ops/s:10 element array对于中等 10,000 个元素吞吐量 ops/s:enter image description here对于大型阵列 1,000,000 个元素吞吐量 ops/s:1M elements

注意:测试运行于

  • 8 中央处理器
  • 1 GB 内存
  • 操作系统版本:16.04.1 LTS(Xenial Xerus)
  • java 版本: 1.8.0_121
  • jvm: -XX:+UseG1GC -server -Xmx1024m -Xms1024m

更新:Java 11在性能上有一些进步,但动态保持不变。

基准测试模式:吞吐量、操作/时间Java 8vs11


推荐