Collector收集器的高级用法

2023-12-30 09:28

本文主要是介绍Collector收集器的高级用法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Collectors收集器的高级用法

pexels-pixabay-265631

 

场景1:获取关联的班级名称

原先如果需要通过关联字段拿到其他表的某个字段,只能遍历List匹配获取

for (Student student : studentList) {Long clazzId = student.getClazzId();// 遍历班级列表,获取学生对应班级名称for (Clazz clazz : clazzList) {if(ObjectUtil.equal(clazzId, clazz.getClazzId())) {student.setClazzName(clazz.getClazzName());break;}}
}

但是如果使用 toMap 方法,可以一步到位,代码的可读性是不是要比上面那种方式好很多?

Map<Long, String> clazzMap = clazzList.stream().collect(Collectors.toMap(Clazz::getClazzId, Clazz::getClazzName));
// 使用Map进行匹配,直接通过get方法获取班级名称
studentList.forEach(i -> i.setClazzName(clazzMap.get(i.getClazzId())));

如果你想关联整个对象而不是某个字段,也没关系,可以像下面这样

Map<Long, Clazz> clazzMap = clazzList.stream().collect(Collectors.toMap(Clazz::getClazzId, Function.identity()));
// 使用Map关联班级对象
studentList.forEach(i -> i.setClazz(clazzMap.get(i.getClazzId())));

 

场景2:统计图书的借阅次数

有一些时候,我们需要对列表的数据做一些统计,比如图书的借阅次数,活动的参与人数等,这些统计可以通过循环手动遍历进行计算

for (BookInfo bookInfo : bookList) {long borrowNumber = 0L;Long bookId = bookInfo.getBookId();for (BorrowRecord record : recordList) {// 次数+1if(ObjectUtil.equal(bookId, record.getBookId())) {borrowNumber ++;}}bookInfo.setBorrowNumber(borrowNumber);
}

上面的这种写法其实还好,但是业务如果复杂一些的话,写起来就比较麻烦了,但是如果使用 toMap 方法,可以一步到位

Map<Long, Long> numberMap = recordList.stream().collect(Collectors.toMap(BorrowRecord::getBookId, e -> 1L, Long::sum));
// 统计图书的借阅次数
bookList.forEach(i -> i.setBorrowNumber(numberMap.get(i.getBookId())));

 

场景3:根据城市分组,查看城市都有哪些姓氏的人

有些业务场景比较复杂,需要对我们对数据进行分组统计,这些情况下,就需要用到 groupingBy() 方法了

Map<City, Set<String>> lastNamesByCity= people.stream().collect(Collectors.groupingBy(Person::getCity,Collectors.mapping(Person::getLastName, Collectors.toSet())));

上面的方法,其实不是唯一的写法,我们还可以这样写

Map<City, Set<String>> lastNamesByCity= people.stream().collect(Collectors.groupingBy(Person::getCity,Collectors.flatMapping((i) -> Stream.of(i.getLastName()), Collectors.toSet())));

Map 也可以间接实现分组的效果,让我们换成 toMap() 方法试试

Map<City, Set<String>> lastNamesByCity= people.stream().collect(Collectors.toMap(Person::getCity, (v) -> {Set<String> set = Sets.newHashSet();set.add(v.getLastName());return set;},(a, b) -> {(a).addAll(b);return a;}, HashMap::new));

另外,如果最后的统计不要求姓氏写成集合,那么我们还可以写成这样

 Map<City, String> lastNamesByCity= people.stream().collect(Collectors.toMap(Person::getCity,Person::getLastName, (a, b) -> a + "," + b));

能看得出来,在分组这件事上,groupingBy() 方法更适合,使用 toMap() 方法虽然也能实现,但是写出的代码会更复杂。

 

场景4:根据客户名称分组,查看订单都有哪些商品

如果需要做购物商城一类的项目,那么必然就离不开订单、用户和商品,根据客户统计订单商品,也是一个非常复杂的业务逻辑,因此这里我们可以用到 groupingBy() 方法

Map<String, Set<Product>> productsByCustomerName= orders.stream().collect(Collectors.groupingBy(Order::getCustomName,Collectors.flatMapping(order -> order.getProducts().stream(),Collectors.toSet())));

让我们换一种写法试试

Map<String, Set<Product>> productsByCustomerName= orders.stream().collect(Collectors.groupingBy(Order::getCustomName,Collectors.collectingAndThen(Collectors.toSet(),i -> i.stream().flatMap(p -> p.getProducts().stream()).collect(Collectors.toSet()))));

换成 toMap() 如何

Map<String, Set<Product>> productsByCustomerName= orders.stream().collect(Collectors.toMap(Order::getCustomName,(v) -> Sets.newHashSet(v.getProducts()),(a, b) -> {(a).addAll(b);return a;})
);

 

场景5:根据部门分组,查看工资大于2000的员工

说到部门,那就不得不提到人员,对人员的各种信息进行统计,我们依然可以使用 groupingBy() 方法

Map<Department, Set<Employee>> wellPaidEmployeesByDepartment= employees.stream().collect(Collectors.groupingBy(Employee::getDepartment,Collectors.filtering(e -> e.getSalary() > 2000,Collectors.toCollection(HashSet::new))));

同样地,如果你喜欢使用 toMap(),也可以像下面这样写

Map<Department, Set<Employee>> wellPaidEmployeesByDepartment= employees.stream().filter(e -> e.getSalary() > 2000).collect(Collectors.toMap(Employee::getDepartment,Sets::newHashSet,(a, b) -> {(a).addAll(b);return a;}));

 

场景6:区分及格和不及格的学生

统计学生的成绩是一大麻烦事,很多数据需要统计到,但如果只是区分及格和不及格的学生,这里我们可以使用 partitioningBy() 方法,将学生分为两个区间

 Map<Boolean, List<Student>> passingFailing = students.stream().collect(Collectors.partitioningBy(s -> s.getGrade() >= DataUtils.PASS_THRESHOLD));

partitioningBy 相当于另一种版本的 groupingBy,但是数据最多只有两组,因为 partitioningBy 是通过指定的条件进行分组的,满足的在一边,不满足的在另一边。

 

场景7:同时统计订单数以及综合评分

JDK12 开始,Collectors 新增了一个方法 teeing,直译为发球,这样翻译可能听不太懂,但我给你看一下怎么用,你就知道了

Pair<Map<Long, Long>, Map<Long, Double>> pair = orderList.stream().collect(Collectors.teeing(Collectors.groupingBy(BookOrder::getHotelId, Collectors.counting()),Collectors.groupingBy(BookOrder::getHotelId, Collectors.averagingDouble(BookOrder::getOrderRating)),Pair::of));
  Collectors.groupingBy(BookOrder::getHotelId, Collectors.counting()),Collectors.groupingBy(BookOrder::getHotelId, Collectors.averagingDouble(BookOrder::getOrderRating)),Pair::of));

是的,teeing 方法接收两个参数,这两个参数分别会得出一个结果,把两个结果再进行处理,就是第三个参数,就这么简单。利用这个方法我们可以分别统计两个结果(比如最值,平均数)并对这两个结果再进行处理,非常好用

这篇关于Collector收集器的高级用法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/552411

相关文章

全面解析Golang 中的 Gorilla CORS 中间件正确用法

《全面解析Golang中的GorillaCORS中间件正确用法》Golang中使用gorilla/mux路由器配合rs/cors中间件库可以优雅地解决这个问题,然而,很多人刚开始使用时会遇到配... 目录如何让 golang 中的 Gorilla CORS 中间件正确工作一、基础依赖二、错误用法(很多人一开

Java Stream流之GroupBy的用法及应用场景

《JavaStream流之GroupBy的用法及应用场景》本教程将详细介绍如何在Java中使用Stream流的groupby方法,包括基本用法和一些常见的实际应用场景,感兴趣的朋友一起看看吧... 目录Java Stream流之GroupBy的用法1. 前言2. 基础概念什么是 GroupBy?Stream

Java Spring的依赖注入理解及@Autowired用法示例详解

《JavaSpring的依赖注入理解及@Autowired用法示例详解》文章介绍了Spring依赖注入(DI)的概念、三种实现方式(构造器、Setter、字段注入),区分了@Autowired(注入... 目录一、什么是依赖注入(DI)?1. 定义2. 举个例子二、依赖注入的几种方式1. 构造器注入(Con

详解MySQL中JSON数据类型用法及与传统JSON字符串对比

《详解MySQL中JSON数据类型用法及与传统JSON字符串对比》MySQL从5.7版本开始引入了JSON数据类型,专门用于存储JSON格式的数据,本文将为大家简单介绍一下MySQL中JSON数据类型... 目录前言基本用法jsON数据类型 vs 传统JSON字符串1. 存储方式2. 查询方式对比3. 索引

全面掌握 SQL 中的 DATEDIFF函数及用法最佳实践

《全面掌握SQL中的DATEDIFF函数及用法最佳实践》本文解析DATEDIFF在不同数据库中的差异,强调其边界计算原理,探讨应用场景及陷阱,推荐根据需求选择TIMESTAMPDIFF或inte... 目录1. 核心概念:DATEDIFF 究竟在计算什么?2. 主流数据库中的 DATEDIFF 实现2.1

MySQL中的LENGTH()函数用法详解与实例分析

《MySQL中的LENGTH()函数用法详解与实例分析》MySQLLENGTH()函数用于计算字符串的字节长度,区别于CHAR_LENGTH()的字符长度,适用于多字节字符集(如UTF-8)的数据验证... 目录1. LENGTH()函数的基本语法2. LENGTH()函数的返回值2.1 示例1:计算字符串

Java中的数组与集合基本用法详解

《Java中的数组与集合基本用法详解》本文介绍了Java数组和集合框架的基础知识,数组部分涵盖了一维、二维及多维数组的声明、初始化、访问与遍历方法,以及Arrays类的常用操作,对Java数组与集合相... 目录一、Java数组基础1.1 数组结构概述1.2 一维数组1.2.1 声明与初始化1.2.2 访问

MySQL 中的 CAST 函数详解及常见用法

《MySQL中的CAST函数详解及常见用法》CAST函数是MySQL中用于数据类型转换的重要函数,它允许你将一个值从一种数据类型转换为另一种数据类型,本文给大家介绍MySQL中的CAST... 目录mysql 中的 CAST 函数详解一、基本语法二、支持的数据类型三、常见用法示例1. 字符串转数字2. 数字

Python中你不知道的gzip高级用法分享

《Python中你不知道的gzip高级用法分享》在当今大数据时代,数据存储和传输成本已成为每个开发者必须考虑的问题,Python内置的gzip模块提供了一种简单高效的解决方案,下面小编就来和大家详细讲... 目录前言:为什么数据压缩如此重要1. gzip 模块基础介绍2. 基本压缩与解压缩操作2.1 压缩文

解读GC日志中的各项指标用法

《解读GC日志中的各项指标用法》:本文主要介绍GC日志中的各项指标用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、基础 GC 日志格式(以 G1 为例)1. Minor GC 日志2. Full GC 日志二、关键指标解析1. GC 类型与触发原因2. 堆