一文带你了解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实现二维码和背景图的合并

    利用java实现二维码和背景图的合并

    本文介绍如何使用java代码将自动生成的二维码放入背景模板中,对于java学习者或许有帮助,一起来看看。
    2016-07-07
  • Java中断异常的正确处理方法

    Java中断异常的正确处理方法

    这篇文章主要给大家介绍了关于Java中断异常的正确处理方法,文中通过示例代码介绍的非常详细,对大家学习或者使用Java具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-09-09
  • Spring Boot中@Autowired注入为空的原因以及解决方法

    Spring Boot中@Autowired注入为空的原因以及解决方法

    最近在开发中遇到了使用@Autowired注解自动装配时会报空指针,发现对象并没有装配进来,下面这篇文章主要给大家介绍了关于Spring Boot中@Autowired注入为空的原因以及解决方法,需要的朋友可以参考下
    2024-01-01
  • Java并发编程数据库与缓存数据一致性方案解析

    Java并发编程数据库与缓存数据一致性方案解析

    这篇文章主要为大家介绍了Java并发编程中数据库与缓存数据一致性解决方案,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2022-04-04
  • java中Ajax与Axios的使用小结

    java中Ajax与Axios的使用小结

    在项目中我们经常会遇到需要向请求头中添加消息的场景,本文主要介绍了java中Ajax与Axios的使用小结,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧
    2024-02-02
  • java实现字符串四则运算公式解析工具类的方法

    java实现字符串四则运算公式解析工具类的方法

    今天小编就为大家分享一篇java实现字符串四则运算公式解析工具类的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-07-07
  • Java详解数据类型的定义与使用

    Java详解数据类型的定义与使用

    Java 是一种类型安全语言,编译器存储在变量中的数值具有适当的数据类型。学习任何一种编程语言都要了解其数据类型,本文将详细介绍 Java 中的数据类型
    2022-04-04
  • SpringBoot集成ShedLock实现分布式定时任务流程详解

    SpringBoot集成ShedLock实现分布式定时任务流程详解

    ShedLock是一个锁,官方解释是他永远只是一个锁,并非是一个分布式任务调度器。一般shedLock被使用的场景是,你有个任务,你只希望他在单个节点执行,而不希望他并行执行,而且这个任务是支持重复执行的
    2023-02-02
  • Idea里github的图形化操作配置方法

    Idea里github的图形化操作配置方法

    这篇文章主要介绍了Idea里github的图形化操作配置方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-02-02
  • SpringBoot启动指定profile的多种方式

    SpringBoot启动指定profile的多种方式

    这篇文章主要介绍了SpringBoot启动指定profile的多种方式,本文通过图文实例相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-09-09

最新评论