需要过滤适合其字段的某些情况的所有对象。 假设对象有几个字段:
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框架,但我没有得出明确的结论。
答案 0 :(得分:4)
不要担心性能,毕竟过早优化是万恶之源。它通常远不如设计良好的代码那么重要,可读且易于维护。
衡量绩效很棘手,尤其是涉及streams
时。例如,对于较小的列表,您可能会发现parallel
比sequential
慢,因为线程的开销超过了增益。您还会发现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()));
}
}
}