一文带你了解Java8 Stream流处理中的收集器技巧

 更新时间:2023年08月23日 08:55:41   作者:努力的IT小胖子  
Java 8 引入的 Stream 极大地简化了集合数据的处理,提供了一种现代、函数式的方式来处理数据,本文将深入探讨 Java 8 Stream 中的收集器,希望对大家有所帮助

Java 8 引入的 Stream 极大地简化了集合数据的处理,提供了一种现代、函数式的方式来处理数据。然而,在处理流时,我们经常需要将流的结果汇总到集合中或者进行各种统计计算。这就是收集器(Collectors)发挥作用的地方。本文将深入探讨 Java 8 Stream 中的收集器,介绍收集器的各种用法和技巧,帮助你更好地利用收集器处理数据。

什么是收集器(Collectors)

收集器是 Stream 提供的一个重要功能,用于将流的元素收集到一个结果容器中。通过使用收集器,可以让代码更加方便的进行简化与重用。其内部主要核心是通过 Collectos 完成更加复杂的计算转换从而获取到最终结果。

Java 8 在 Collectors 类中预定义了多个用于收集的方法,使得我们可以轻松地对流的元素进行汇总、分组、分区以及其他各种操作。

常见的收集器用法

通过 toList 将元素收集到集合中

List<String> names = peopleStream.map(Person::getName)
                                 .collect(Collectors.toList());

通过 counting 统计集合总数

Long collect = studentList.stream().collect(Collectors.counting());

通过 maxBy 和 minBy 获取最大值最小值

Optional<Student> optional = studentList.stream().collect(Collectors.maxBy(Comparator.comparing(Student::getAge));)
if (optional.isPresent()){
    Student student = optional.get();
    System.out.println(student);
}

通过 summingLnt 进行数据汇总

Integer collect  = peopleStream.collect(Collectors.summingLnt(Person::getAge));
int sum = peopleStream.mapToInt(Person::getAge).sum();

通过 averagingLnt 进行平均值获取

Double collect  = peopleStream.collect(Collectors.averagingLnt(Person::getAge));

其内部是在收集过程中,对所有年龄进行累加,最后除以平均值

通过 joining 进行数据拼接

Person collect  = peopleStream.collect(Collectors.joining());

这种方式相当于将流中每一个元素的name属性获取映射,内部通过StringBuilder来把每一个映射的值进行拼接。

通过 groupingBy 将数据进行分组

Map<Integer,List<Student>> map = peopleStream.collect(Collectors.groupingBy(Person::getAge));

自定义收集器

已经通过Collectors中提供的静态方法,完成了诸多的收集器操作,虽然它本身提供了诸多方法,但是不一定能够覆盖日常开发中的所有需求,因此,有时还需要我们根据自身的业务去自定义收集器的实现。通过实现 Collector 接口,我们可以完全掌控收集的过程。

源码分析

根据源码,Collector 接口需要三个参数。

  • T: 流中要收集的元素类型
  • A: 累加器的类型
  • R:收集的结果类型

如果想要自定义收集器,需要实现 Collector 接口中的五个方法 Supplier、Accumulator、finisher、combiner、characteristics

supplier:用于创建一个容器,在调用它时,需要创建一个空的累加器实例,供后续方法使用。

accumulator:基于supplier中创建的累加容器,进行累加操作。

finisher:当遍历完流后,在其内部完成最终转换,返回一个最终结果。

combiner:用于在并发情况下,将每个线程的容器进行合并。

characteristics:用于定义收集器行为,如是否可以并行或使用哪些优化。其本身是一个枚举,内部有三个值,分别为:

  • CONCURRENT:表明收集器是并行的且只会存在一个中间容器。
  • UNORDERED:表明结果不受流中顺序影响,收集是无序的。
  • IDENTITY_FINISH:表明累积器的结果将会直接作为归约的最终结果,跳过finisher()。

实战示例:收集合格的学生

定义自定义收集器

package com.jdk8.features.stream.collector;
import com.jdk8.features.lambda.Student;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
public class MyCollector implements Collector<Student, List<Student>,List<Student>> {
  @Override
  public Supplier<List<Student>> supplier() {
    return ArrayList::new;
  }
  @Override
  public BiConsumer<List<Student>, Student> accumulator() {
    return ((studentList, student) -> {
      if (student.getIsPass()){
        studentList.add(student);
      }
    });
  }
  @Override
  public BinaryOperator<List<Student>> combiner() {
    return null;
  }
  @Override
  public Function<List<Student>, List<Student>> finisher() {
    return Function.identity();
  }
  @Override
  public Set<Characteristics> characteristics() {
    return EnumSet.of(Characteristics.IDENTITY_FINISH,Characteristics.UNORDERED);
  }
}

使用自定义收集器

import com.jdk8.features.lambda.Student;
import java.util.ArrayList;
import java.util.List;
public class MyCollectorDemo {
  public static void main(String[] args) {
    List<Student> studentList = new ArrayList<>();
    studentList.add(new Student(1,"张三",18,19));
    studentList.add(new Student(2,"李四",19,18));
    studentList.add(new Student(3,"王五",20,21));
    studentList.add(new Student(4,"赵六",21,80));
    List<Student> list = studentList.stream().collect(new MyCollector());
    System.out.println(list);
  }
}

结语

掌握收集器的使用是精通 Java 8 Stream 不可或缺的一部分。在处理流数据时,收集器可以帮助我们更轻松地完成数据的汇总、分组、分区等操作。通过本文的介绍,相信你已经对收集器有了更深入的了解,并能够在实际项目中灵活运用收集器的各种技巧。让我们在流处理的旅程中更加游刃有余!

到此这篇关于一文带你了解Java8 Stream流处理中的收集器技巧的文章就介绍到这了,更多相关Java8 Stream内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java中对list集合进行分页的四种方式介绍

    Java中对list集合进行分页的四种方式介绍

    这篇文章主要为大家详细介绍了Java中对list集合进行分页的四种方式,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以了解下
    2025-12-12
  • java+mysql模拟实现银行系统

    java+mysql模拟实现银行系统

    这篇文章主要为大家详细介绍了java+mysql模拟实现银行系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-05-05
  • springboot2.1.3配置sftp自定义sftp连接池的详细过程

    springboot2.1.3配置sftp自定义sftp连接池的详细过程

    这篇文章主要介绍了springboot2.1.3配置sftp自定义sftp连接池的详细过程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-08-08
  • SpringBoot和Vue实现动态二维码的示例代码

    SpringBoot和Vue实现动态二维码的示例代码

    二维码在现代社交和营销活动中被广泛使用,本文主要介绍了SpringBoot和Vue实现动态二维码的示例代码,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧
    2024-02-02
  • Java依赖倒转原则_动力节点Java学院整理

    Java依赖倒转原则_动力节点Java学院整理

    这篇文章主要介绍了Java依赖倒转原则的定义及问题由来解决方案,感兴趣的朋友一起看看吧
    2017-08-08
  • MyBatis中#{}占位符与${}拼接符的用法说明

    MyBatis中#{}占位符与${}拼接符的用法说明

    这篇文章主要介绍了MyBatis中#{}占位符与${}拼接符的用法说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • java中"==" 与equals方法的使用

    java中"==" 与equals方法的使用

    本篇文章介绍了,在java中"==" 与equals方法的使用。需要的朋友参考下
    2013-04-04
  • SpringBoot中使用Swagger的超简单方法

    SpringBoot中使用Swagger的超简单方法

    大家一致认为springBoot使用swagger太麻烦了,每次都需要编写config,今天小编告诉大家一种超简单配置方法,教大家如何整合swagger,感兴趣的朋友跟随小编一起看看吧
    2021-07-07
  • @PathVariable和@RequestParam传参为空问题及解决

    @PathVariable和@RequestParam传参为空问题及解决

    这篇文章主要介绍了@PathVariable和@RequestParam传参为空问题及解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • Java数组转换为List的四种方式

    Java数组转换为List的四种方式

    这篇文章主要介绍了Java开发技巧数组转List的四种方式总结,每种方式结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-09-09

最新评论