java中Stream API中“filter()”方法的性能[重复]

Posted

技术标签:

【中文标题】java中Stream API中“filter()”方法的性能[重复]【英文标题】:Performance of "filter()" method in Stream API in java [duplicate] 【发布时间】:2021-05-22 18:55:27 【问题描述】:

我想知道java的流API处理这两种情况的方式是相同的还是不同的?如果它要为每个过滤器执行一个独立的循环,那么我认为在性能方面存在显着差异。你觉得怎么样?

这是两个条件

 1. filter(cond1 && cond2 && cond3)
 2. filter(cond1).filter(cond2).filter(cond3)

例子

List<Employee> emps1 = employees.stream()                                                     
        .filter((Employee e) -> e.name.endsWith("n") && e.salary > 10000 && e.id % 2 == 1)    
        .collect(Collectors.toList());                                                        
                                                                                              
List<Employee> emps2 = employees.stream()                                                     
        .filter(e -> e.name.endsWith("n"))                                                    
        .filter(e -> e.salary > 10000)                                                        
        .filter(e -> e.id % 2 == 1)                                                           
        .collect(Collectors.toList());                                                        

【问题讨论】:

读取选项,第一个将与“ands”连接的条件应用于整个数据,其他将 cond1 应用于整个数据,其他每个应用于缩减集。我对你的建议是用你拥有的数据来衡量自己——我想即使你交换条件顺序,它们也会出现差异。 TLDR:编译器处理它的方式不同。我们可以参考这个***.com/a/48513110/1285923。他们在字节码级别对编译器如何处理它进行了分析。性能方面,IMO 不会有太大差别,唯一的优化是在算子短路上。 在更容易阅读的地方编写代码,第二个似乎是这样做的方式。性能方面,几乎没有差异 任何性能问题只有通过基准测试才能真正得到回答。假设只能到此为止。我建议你对代码进行基准测试并找出答案。 【参考方案1】:

filter(cond1 &amp;&amp; cond2 &amp;&amp; cond3) 的情况下,只要任何条件评估为false,条件处理就会停止,例如如果cond1 的计算结果为false,则不会处理其他条件(cond2cond3)。同样,如果 cond1 计算为 true,则处理将继续计算 cond2,如果计算结果为 false,则不会计算条件 cond3

filter(cond1).filter(cond2).filter(cond3)的处理方式也是一样的,从下面的例子可以看出:

import java.util.stream.Stream;

public class Main 
    public static void main(String[] args) 
        Stream.of("one", "two", "three", "four")
        .filter(s -> 
            System.out.println("Hello");
            return s.contains("t");
        )
        .filter(s -> 
            System.out.println("Hi");
            return s.contains("f");
        )
        .forEach(System.out::println);
    

输出:

Hello
Hello
Hi
Hello
Hi
Hello

因此,它没有任何区别,这是一个选择问题。第二个看起来更干净。


注意:对于更复杂的表达式,您可以使用Predicate#and,它还有两个好处:

    您可以在代码中将Predicate 实现的行为与其他流重用。 更简洁的代码。

演示:

import java.util.function.Predicate;
import java.util.stream.Stream;

public class Main 
    public static void main(String[] args) 
        Predicate<String> containsT = s -> s.contains("t");
        Predicate<String> containsE = s -> s.contains("e");
        
        Stream.of("one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten")
                .filter(containsT.and(containsE))
                .forEach(System.out::println);
    

输出:

three
eight
ten

但是,它对处理的方式没有任何影响。

【讨论】:

"在 filter(cond1).filter(cond2).filter(cond3) 的情况下,所有的条件都会被评估。 - 有来源吗?我不相信这是普遍正确的,如果有的话。 我知道流处理是如何工作的,但是所有过滤器都针对每个元素执行的想法是错误的;如果他们没有通过第一个过滤器,则不会评估连续的过滤器。 ideone.com/yjOS8u

以上是关于java中Stream API中“filter()”方法的性能[重复]的主要内容,如果未能解决你的问题,请参考以下文章

java 8 学习三(Stream API)

java stream Api

Go 通过 Map/Filter/ForEach 等流式 API 高效处理数据

java8 stream.filter 过滤集合中的数据

使用 Stream API 简化集合操作

Java8: Stream API