在Java流的性能方面有什么好处:结合过滤器或结合环境?

时间:2018-05-01 14:12:48

标签: java parallel-processing java-stream

需要过滤适合其字段的某些情况的所有对象。 假设对象有几个字段:

class Price {
int first;
int second; 
String third; 
}

和价格流:

Stream<Price> streamPrices; 

最佳选择是什么:

1

streamPrices
    .parallel()
    .filter(p0->p0.first> 10)
    .filter(p1->p1.second <30)
    .filter(p2-> p2.third.length() > 8);

2

streamPrices
   .parallel()
   .filter(p-> (p.first > 10) 
      && (p->p.second <30) 
      && (p-> p.third.length() > 8)
    );

我使用了JMH框架,但我没有得出明确的结论。

2 个答案:

答案 0 :(得分:4)

不要担心性能,毕竟过早优化是万恶之源。它通常远不如设计良好的代码那么重要,可读且易于维护。

衡量绩效很棘手,尤其是涉及streams时。例如,对于较小的列表,您可能会发现parallelsequential慢,因为线程的开销超过了增益。您还会发现streams通常效率低于传统iterators,因为流是编译器变成对象和方法调用的语法糖。

话虽如此,差异是微不足道的,甚至不值得再次思考。

答案 1 :(得分:-1)

使用您的价格等级进行测量,其中第一个过滤器移除50%,第二个过滤器移除下一个50%,第三个过滤器移除50%,因为方法编号2比方法编号1长一半多。

修改:在评论中遵循Lino的建议改进了数字,但数字略有下降,但方法1的数据仍然下降了50%。

方法1:118毫秒 / 10000000件

平均值:118ms min:107ms,最大值:252ms

方法2:79毫秒 / 10000000件

平均值:79ms min:70ms,最大值:91ms

所以方法2 肯定更具性能,但实际差异在我的计算机上小于40毫秒/ 1000万个项目,所以除非你使用非常大的设置,否则它可以忽略不计。

我个人更喜欢方法1,因为它更容易阅读。如果从另一个函数传递谓词,方法2会很有用。

public class FilterTest extends Test {
int i = 10000000;
Random random = new Random(i);
List<Price> prices;

public void setup() {
    prices = Stream.generate(new Supplier<Price>() {
        @Override
        public Price get() {
            return new Price(random);
        }
    }).limit(i).collect(Collectors.toList());
}

@Override
public void run() {
    // Method 1
    // prices.stream().parallel()
    //     .filter(p -> p.v1 > 0.5d)
    //     .filter(p -> p.v2 > 0.5d)
    //     .filter(p -> p.s.length() > 16)
    //     .collect(Collectors.toList());

    // Method 2
    prices.stream().parallel()
            .filter(p -> p.v1 > 0.5d && p.v2 > 0.5 && p.s.length() > 16)
            .collect(Collectors.toList());
}

public static class Price {
    double v1, v2;
    String s;

    public Price(Random random) {
        this.v1 = random.nextDouble();
        this.v2 = random.nextDouble();
        this.s = UUID.randomUUID().toString().substring(0,(int)(32*random.nextDouble()));
    }
}
}