我有一个队友,他在一次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相关问答推荐

AWS Java SDK 2(putTarget)+ MinIO:不支持您提供的授权机制.请使用AWS 4-HMAC-SHA 256

从头开始使用Jgit初始化InMemoryRepository

如何在PFA中使用不确定的进度指标制作可暂停的任务?

Saxon 9:如何从Java扩展函数中的net.sf.saxon.expr. XPathContent中获取声明的变量

Java JAR环境(JRE)是否支持模块?

当切换javaFX场景时,stage的大小正在Minimize

我想了解Java中的模块化.编译我的应用程序时,我有一个ResolutionException

上下文初始化期间遇到异常-使用Java配置配置HibernateTemplate Bean时

如何使用AWS CLI从S3存储桶中的所有对象中删除用户定义的元数据?

Java中如何根据Font.canDisplay方法对字符串进行分段

Jakarta CDI强制bean构造/注册遗留事件侦听器

安装Java Jar应用程序的Install4j遇到ClassNotFoundException的运行时错误

在Java 17中使用两个十进制数字分析时间时出错,但在Java 8中成功

Spring安全令牌刷新和JWT签名与本地计算的签名不匹配

如何读取3个CSV文件并在控制台中按顺序显示?(Java)

带有可选部分的Java DateTimeForMatter

JFree Chart从图表中删除边框

有没有办法知道在合并中执行了什么操作?

在应用getCellFormula()时,Excel引用中的文件名始终为";[1]";使用Apache POI()

在Java中将.GRF转换为图像文件