我有一个队友,他在一次Foreach执行中完成了所有的流操作.我试图找出使用Filter、map和to list方法的优点.

除了可读性之外,它还有什么其他优势(可以说,Foreach也非常易读) 以下是与他的所作所为相似的内容的片段:

List<Integer> firstInts = new ArrayList<>();
List<Integer> secondInts = new ArrayList<>();
List<Integer> numbersList = IntStream.range(0, max).boxed().toList();


//his stream
numbersList.stream()
       .forEach(i -> {
           if(i % 6 != 0) {
               return;
           }
           secondInts.add(i);
       });


//alternative 1
numbersList.stream()
        .filter(i -> i % 6 == 0)
        .forEach(firstInts::add);


//alternative 2
List<Integer> third = numbersList.stream()
        .filter(i -> i % 6 == 0)
        .toList();

除了可读性之外,使用流方法的动机是什么?

推荐答案

在这种情况下, Select 2对我来说是最好的

1.可读性

  • 备选方案2的行数较少
  • 备选方案2的读数更接近return a list containing number divisible by 6 from numList,而forEach方法意味着将可被6整除的数字从数字列表添加到secondInts
  • filter(i -> i % 6 == 0)是直截了当的
    if(i % 6 != 0) {
        return;
    }
    
    需要一些时间让人脑进行处理.

2.表演

Stream.toList()

实施说明: 大多数Stream实例将覆盖此方法,并提供与此接口中的实现相比高度优化的实现.

我们从使用Stream API的JDK优化中受益.

在这种情况下,使用forEach并逐个添加元素会更慢,尤其是在列表很大的情况下.这是因为每当列表满时,ArrayList都需要扩展它的容量,而Stream实现ImmutableCollections.listFromTrustedArrayNullsAllowed只是将结果数组存储到ListN中.

One more point to note about parallelism:
From Stream#forEach

此操作的行为显然是不确定的.对于并行流管道,此操作不保证尊重流的相遇顺序,因为这样做会牺牲并行性的好处.对于任何给定的元素,该操作可以在库 Select 的任何时间和线程中执行.如果该操作访问共享状态,则它负责提供所需的同步.

numbersList.stream().parallel()
       .forEach(i -> {
           if(i % 6 != 0) {
               return;
           }
           secondInts.add(i);
       });

将提供意想不到的结果,而

List<Integer> third = numbersList.stream().parallel()
      .filter(i -> i % 6 == 0).sorted().forEach()
      .toList();

完全没问题.

3.灵活性

假设您想要对过滤后的列表进行排序,在forEach方法中,您可以这样做:

numbersList.stream().sorted().
       .forEach(i -> {
           if(i % 6 != 0) {
               return;
           }
           secondInts.add(i);
       });

与之相比要慢得多

numbersList.stream()
        .filter(i -> i % 6 == 0)
        .sorted()
        .toList();

因为我们需要对整个数字列表进行排序,而不是进行筛选.

或者,如果您想将结果限制为10个元素,使用forEach并不直接,而是像使用STREAM时添加limit(10)一样简单.

4.不易出错

流API默认情况下通常返回不可变对象.

Stream.toList()

实施要求: 此接口中的实现返回一个列表,好像是由以下对象生成的: 集合.不可修改列表(新ArrayList<;>;(Arrays.asList(this.toArray())))

这意味着默认情况下返回的列表是不可变的.不变性的一些优势包括:

  1. 您可以安全地将列表传递给不同的方法,而不必担心列表被修改.
  2. 不可变列表是线程安全的.

阅读Pros. / Cons. of Immutability vs. Mutability以进行进一步讨论.

Java相关问答推荐

Java FFM,如何将Java对象与C struct 链接起来?

试图弄清楚资源未能在我的Android应用程序中调用关闭警告

在Keycloak测试容器中的测试之间清理数据库

Android -如何修复Java.time.zone. ZoneRulesExcept:未知时区ID:Europe/Kyiv

Java 22模式匹配不适用于记录模式匹配.给出汇编问题

int Array Stream System. out. print方法在打印Java8时在末尾添加% sign

为什么我的ArrayList索引的索引总是返回-1?

无法在WebSocket onMessage中捕获错误

格式中的特定回录键-值对

在向WebSphere中的文档添加元素时iText挂起

如何在Cosmos DB(Java SDK)中增加默认响应大小

与IntArray相比,ArrayList<;Int>;对于大量元素的性能极差

如何用内置Java从JavaFX应用程序中生成.exe文件?

try 使用预准备语句占位符获取信息时出现Try-With-Resources错误

泛型与泛型问题的完美解决方案?

为了安全起见,有必要复制一份 list 吗?

Maven-Dependency-Plugin 3.6.+开始查找在依赖关系:分析目标期间找到的新的使用的未声明依赖关系

Java HashMap保留所有时间复杂性

如何使用Rascal Evaluator从编译的JAR访问Rascal函数?

如何使用Hibernate v6.2构建NamingStrategy,以表名作为所有列的前缀?