流中“先过滤后映射”和“先映射后过滤”的性能是否有所不同?

Key*_*yzj 6 java java-8 java-stream

我想知道什么更快:按字段过滤自定义对象,然后按其字段映射,反之亦然(先映射,然后过滤)。
最后,我通常希望将映射的字段收集到一些Collection中。

例如,最简单的Person类:

public class Person {
    String uuid;
    String name;
    String secondName;
}
Run Code Online (Sandbox Code Playgroud)

现在让我们来一个List<Person> persons

List<String> filtered1 = persons
                .stream()
                .filter(p -> "NEED_TOY".equals(p.getName()))
                .map(Person::getName)
                .collect(Collectors.toList());
// or?
List<String> filtered2 = persons
                .stream()
                .map(Person::getName)
                .filter(p -> "NEED_TOY".equals(p))
                .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

JB *_*zet 6

在此特定示例中,调用Person.getName()基本上完全没有花费,这没有关系,您应该使用最容易读取的内容(并且过滤可能甚至快一些,因为正如TJ所述,映射操作是其中的一部分过滤操作)。

但是,如果映射操作的成本很高,则首先过滤(如果可能)会更有效率,因为流不必映射已过滤出的元素。

让我们举一个人为的示例:您有一个ID流,并且对于流中的每个偶数ID,您都必须执行http GET请求或数据库查询以获取由该ID标识的商品的详细信息(并因此映射详细对象的ID)。

假设流由一半的偶数ID和一半的奇数ID组成,并且每个请求花费相同的时间,则可以通过首先过滤将时间除以2。如果每个HTTP请求都花费1秒,并且您有60个ID,则通过首先过滤,您将为同一任务从60秒变为30秒,还可以减少网络和外部HTTP API的费用。


Nid*_*nan 6

显然,性能完全取决于

  • 您在流式传输时执行的复杂操作(您的业务逻辑)
  • 您的数据有多复杂

让我们看两个简单的场景

场景1

如果您的映射函数需要执行一些复杂的操作,例如调用一些外部 REST api 来操作流对象,那么在这种情况下,我建议在映射之前先进行过滤,因为它将减少不必要的昂贵 REST 调用。在这种方法中,当我们首先进行过滤时,显然它会对所有匹配对象执行两次映射操作。

在此输入图像描述

场景2

假设您需要首先根据一些外部 REST API 调用或函数操作数据流,然后过滤该结果。显然,在这种情况下,您需要在过滤流之前先进行映射。与前一种方法相比,这种方法可以稍微快一些,因为映射操作是过滤操作的一部分

在此输入图像描述