在 Java 流的性能方面哪个更好:组合过滤器或组合环境? [复制]
Posted
技术标签:
【中文标题】在 Java 流的性能方面哪个更好:组合过滤器或组合环境? [复制]【英文标题】:What's better in terms of performance of a Java stream: combine filters or combine circumstances? [duplicate] 【发布时间】:2018-10-11 14:02:55 【问题描述】:需要过滤适合其字段的某些情况的所有对象。 假设对象有几个字段:
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 框架,但没有得出明确的结论。
【问题讨论】:
我认为第一个更具可读性,这是您在实际遇到性能问题之前唯一应该考虑的事情。 第二个示例是有效的 Java 语法吗?我认为您不能将谓词与逻辑和运算符结合起来。我认为您想删除 lamdas 并仅使用布尔表达式。 【参考方案1】:不用担心性能,毕竟过早的优化是万恶之源。它通常远没有精心设计的可读且易于维护的代码那么重要。
衡量性能很棘手,尤其是在涉及streams
时。例如,对于较小的列表,您可能会发现 parallel
比 sequential
慢,因为线程的开销超过了收益。您还会发现 streams
通常比传统的 iterators
效率低,因为流是编译器将其转换为对象和方法调用的语法糖。
话虽如此,差异是如此微不足道,以至于根本不值得考虑。
【讨论】:
【参考方案2】:使用您的价格等级进行测量,其中第一个过滤器去除 50%,第二个过滤器去除下一个 50%,第三个过滤器去除 50%,结果表明方法 2 所需的时间是方法 1 的一半多一点。
编辑:按照 Lino 在 cmets 中的建议改进了数字,略微减少了数字,但方法 1 总体减少了 50%。
方法 1:118 毫秒 / 10000000 项
平均:118 毫秒,最小:107 毫秒,最大:252 毫秒
方法 2:79 毫秒 / 10000000 项
平均:79 毫秒,最小:70 毫秒,最大:91 毫秒
因此,方法 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()));
【讨论】:
我通过了几乎相同的步骤进行检查。我同意你的观点,第一个更具可读性。 请看看如何proper benchmark @Lino 使测试更正确,但总体结果相同以上是关于在 Java 流的性能方面哪个更好:组合过滤器或组合环境? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
在 C# 的 ToUpper 或 SQL 中的 Upper 函数的性能方面哪个更好