当前位置: 首页 > news >正文

Java Sream中自定义Collector实现复杂数据收集方法

❃博主首页 : 「码到三十五」 ,同名公众号 :「码到三十五」,wx号 : 「liwu0213」
☠博主专栏 : <mysql高手> <elasticsearch高手> <源码解读> <java核心> <面试攻关>
♝博主的话 : 搬的每块砖,皆为峰峦之基;公众号搜索「码到三十五」关注这个爱发技术干货的coder,一起筑基

Java Stream API中的Collector接口是一个强大的工具,它允许我们自定义数据收集、转换和聚合的过程。

文章目录

      • 1. Collector接口的作用
      • 2. Collector接口的组成
      • 3. Collector接口的工作原理
      • 4. Collector的预定义实现Collectors
      • 5. 自定义Collector的使用场景

1. Collector接口的作用

Collector接口定义了数据收集、转换和聚合的基本操作,使得从Stream中收集到特定的数据结构或执行复杂的聚合操作成为可能。Collector接口为Stream操作提供了一个终止方法,将Stream的处理结果收集到一个特定的容器中。

2. Collector接口的组成

Collector接口包含以下五个主要方法:

  1. supplier():返回一个新的结果容器的Supplier。这个方法用于创建用于存储收集结果的容器。

  2. accumulator():接收一个结果容器和一个流中的元素,将元素添加到结果容器中。这是累积元素的核心方法,用于将流中的元素逐个添加到结果容器中。

  3. combiner():接收两个结果容器,合并它们。在并行流处理中,如果有多个结果容器被生成,则使用combiner()方法将它们合并为一个容器。

  4. finisher():接收一个结果容器,返回最终结果。这个方法通常用于将结果容器转换为最终想要的形式,例如,对容器中的元素进行排序或过滤。

  5. characteristics():返回一个不可变的Set,包含收集器的特性。这些特性用于优化流处理过程,如并行流处理或结果的无序性。

3. Collector接口的工作原理

Collector接口的工作原理基于上述五个方法的协作。先通过supplier()方法创建一个新的结果容器。然后,遍历Stream中的每个元素,使用accumulator()方法将元素添加到结果容器中。在并行流处理中,如果有多个结果容器被生成,则使用combiner()方法将它们合并为一个容器。最后,通过finisher()方法将结果容器转换为最终想要的形式,并返回。

4. Collector的预定义实现Collectors

Collectors可以看做是Collector接口的实现工厂,提供了多个用于数据收集、转换和聚合的预定义收集器,如toList()、toSet()、toMap()、joining()、counting()、summingInt()、averagingInt()等。这些收集器利用Collector接口实现,使得从Stream中收集数据变得更为方便和高效。

List<String> list = Stream.of("a", "b", "c")
.collect(Collectors.toList());Map<Character, List<String>> grouped = Stream.of("a", "b", "c")
.collect(Collectors.groupingBy(s -> s.charAt(0)));String joined = Stream.of("a", "b", "c")
.collect(Collectors.joining(", "));

如,toList()收集器通过调用new ArrayList<>()来创建一个新的结果容器,并使用accumulator()方法将流中的元素添加到结果容器中。toMap()收集器则创建一个新的HashMap,并使用提供的键函数和值函数将元素映射到Map的键和值上。

5. 自定义Collector的使用场景

通过实现Collector接口来自定义复杂的收集器,以满足特定的数据处理需求。自定义Collector时,要实现上述五个方法,并定义如何收集、转换和聚合数据。

如,自定义CollectorPerson对象进行排序,并根据特定条件进行分组:

public static class CustomCollector<T> implements Collector<Person, List<Person>, Map<String, List<Person>>> {@Overridepublic Supplier<List<Person>> supplier() {return ArrayList::new;}@Overridepublic BiConsumer<List<Person>, Person> accumulator() {return (list, person) -> list.add(person);}@Overridepublic BinaryOperator<List<Person>> combiner() {return (list1, list2) -> {list1.addAll(list2);return list1;};}@Overridepublic Function<List<Person>, Map<String, List<Person>>> finisher() {return list -> {Map<String, List<Person>> result = new HashMap<>();// 自定义排序规则list.sort((p1, p2) -> {if (p1.age != null && p2.age != null) {return p1.age.compareTo(p2.age);} else if (p1.age != null) {return -1;} else if (p2.age != null) {return 1;} else {return p1.name.compareTo(p2.name);}});// 自定义分组规则for (Person person : list) {if (result.containsKey(person.name.substring(0, 2))) {result.get(person.name.substring(0, 2)).add(person);} else {List<Person> group = new ArrayList<>();group.add(person);result.put(person.name.substring(0, 2), group);}}return result;};}@Overridepublic Set<Collector.Characteristics> characteristics() {return EnumSet.of(Collector.Characteristics.IDENTITY_FINISH);}
}

自定义收集、转换和聚合Person对象的逻辑。使用自定义的排序和分组规则,根据姓名和年龄将Person对象分组并排序,最终返回Map<String, List<Person>>
通过自定义Collector,创建特定的收集器,而满足复杂的数据处理需求。

使用方法:

import java.util.*;
public class CustomCollectorDemo {public static void main(String[] args) {List<Person> people = Arrays.asList(new Person("Alice", 25),new Person("Bob", 23),new Person("Charlie", 28),new Person("David", 25),new Person("Eva", 23),new Person("Frank", 28));Map<String, List<Person>> result = people.stream().collect(new CustomCollector<>());System.out.println(result);}static class Person {String name;Integer age;...}
}

关注公众号[码到三十五]获取更多技术干货 !

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Java 向上转型小白学习总结
  • hive benchmark
  • zdpvue_primeadmin 登录相关界面的代码梳理和优化,一款Vue3开发的后台管理系统模板
  • IDEA如何进行断点调试
  • day 28 HTTP协议
  • C语言第20天笔记
  • 在Java程序中执行Linux命令
  • 对AI大模型的擅长能力的了解
  • 工作 sql 数据库创建 表的修改 插入数据
  • 数据库系统 第17节 数据仓库
  • 分享|华为测试OD岗面试流程
  • 高效记录与笔记整理的策略:工具选择、结构设计与复习方法
  • CentOS 上安装 Java 17
  • 【Bifrost】ubuntu24.04 远程构建及clion设置编码风格google
  • docker入门教程
  • [译] 怎样写一个基础的编译器
  • Android 初级面试者拾遗(前台界面篇)之 Activity 和 Fragment
  • Android路由框架AnnoRouter:使用Java接口来定义路由跳转
  • CSS盒模型深入
  • go语言学习初探(一)
  • Java IO学习笔记一
  • Magento 1.x 中文订单打印乱码
  • magento 货币换算
  • nfs客户端进程变D,延伸linux的lock
  • spring boot 整合mybatis 无法输出sql的问题
  • ⭐ Unity 开发bug —— 打包后shader失效或者bug (我这里用Shader做两张图片的合并发现了问题)
  • Vue.js-Day01
  • WordPress 获取当前文章下的所有附件/获取指定ID文章的附件(图片、文件、视频)...
  • 从0到1:PostCSS 插件开发最佳实践
  • 从零开始的webpack生活-0x009:FilesLoader装载文件
  • 给自己的博客网站加上酷炫的初音未来音乐游戏?
  • 微信小程序填坑清单
  • 主流的CSS水平和垂直居中技术大全
  • 转载:[译] 内容加速黑科技趣谈
  • 深度学习之轻量级神经网络在TWS蓝牙音频处理器上的部署
  • ​LeetCode解法汇总307. 区域和检索 - 数组可修改
  • ​油烟净化器电源安全,保障健康餐饮生活
  • ‌U盘闪一下就没了?‌如何有效恢复数据
  • ###STL(标准模板库)
  • #Datawhale AI夏令营第4期#AIGC文生图方向复盘
  • #我与虚拟机的故事#连载20:周志明虚拟机第 3 版:到底值不值得买?
  • (24)(24.1) FPV和仿真的机载OSD(三)
  • (C)一些题4
  • (C++)栈的链式存储结构(出栈、入栈、判空、遍历、销毁)(数据结构与算法)
  • (多级缓存)多级缓存
  • (二十六)Java 数据结构
  • (论文阅读26/100)Weakly-supervised learning with convolutional neural networks
  • (论文阅读31/100)Stacked hourglass networks for human pose estimation
  • (免费领源码)python#django#mysql校园校园宿舍管理系统84831-计算机毕业设计项目选题推荐
  • (切换多语言)vantUI+vue-i18n进行国际化配置及新增没有的语言包
  • (十)【Jmeter】线程(Threads(Users))之jp@gc - Stepping Thread Group (deprecated)
  • (十二)springboot实战——SSE服务推送事件案例实现
  • (四)模仿学习-完成后台管理页面查询
  • (一)为什么要选择C++
  • *2 echo、printf、mkdir命令的应用