在 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 时。例如,对于较小的列表,您可能会发现 parallelsequential 慢,因为线程的开销超过了收益。您还会发现 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 流的性能方面哪个更好:组合过滤器或组合环境? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

在性能 Lambda 或简单循环方面哪个更好? [复制]

性能方面哪个更好:对象原型还是构造函数本机函数? [复制]

在 C# 的 ToUpper 或 SQL 中的 Upper 函数的性能方面哪个更好

哪个更好?数组、ArrayList 或 List<T>(在性能和速度方面)

Java数据库,哪个更好用?

连接中过滤器的 SQL 性能与结果中的 SQL 性能