Java多字段分组取最新记录技巧
2025-09-13 13:36:45
0浏览
收藏
哈喽!大家好,很高兴又见面了,我是golang学习网的一名作者,今天由我给大家带来一篇《Java多字段分组筛选最新记录方法》,本文主要会讲到等等知识点,希望大家一起学习进步,也欢迎大家关注、点赞、收藏、转发! 下面就一起来看看吧!
业务场景概述
在实际开发中,我们经常会遇到需要处理包含重复数据的列表,但这些重复数据在某些关键字段上是唯一的。例如,一个员工列表可能包含同一个员工(通过姓氏和名字确定)在不同时间点的薪资记录。我们的目标是,对于每个唯一的员工组合(例如,相同的姓氏和名字),只保留其最新的一条记录。
假设我们有以下Employee类定义:
import lombok.AllArgsConstructor; import lombok.Data; import java.time.LocalDate; @Data @AllArgsConstructor public class Employee { private String firstName; private String lastName; private double salary; private LocalDate date; // 使用LocalDate表示日期 }
以及一个包含示例数据的List
import java.util.ArrayList; import java.util.List; import java.time.LocalDate; public class EmployeeData { public static List<Employee> getSampleEmployees() { List<Employee> employees = new ArrayList<>(); employees.add(new Employee("John", "Smith", 10, LocalDate.of(2022, 9, 1))); employees.add(new Employee("John", "Smith", 20, LocalDate.of(2022, 10, 1))); employees.add(new Employee("John", "Smith", 5, LocalDate.of(2022, 11, 1))); employees.add(new Employee("Kelly", "Jones", 12, LocalDate.of(2022, 3, 1))); employees.add(new Employee("Sara", "Kim", 21, LocalDate.of(2022, 3, 1))); employees.add(new Employee("Sara", "Kim", 7, LocalDate.of(2022, 7, 1))); return employees; } }
我们的目标是得到以下结果:
- "John", "Smith", 5, 2022-11-01 (最新日期)
- "Kelly", "Jones", 12, 2022-03-01 (唯一记录)
- "Sara", "Kim", 7, 2022-07-01 (最新日期)
使用 Java Stream API 解决问题
Java 8 引入的 Stream API 为处理集合数据提供了强大而简洁的工具。对于上述需求,我们可以利用Collectors.toMap的重载方法,该方法允许我们定义一个合并函数来处理键冲突。
核心思路
- 生成唯一的键: 对于每个Employee对象,我们需要一个唯一的键来表示一个特定的员工。在这个例子中,firstName和lastName的组合构成了这个键。
- 处理键冲突: 当两个或多个Employee对象生成相同的键时(即它们是同一个员工),我们需要一个策略来决定保留哪一个。在本例中,我们希望保留日期最新的那条记录。
示例代码
import java.util.Collection; import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; import java.time.LocalDate; public class EmployeeFilterTutorial { public static void main(String[] args) { List<Employee> employees = EmployeeData.getSampleEmployees(); Collection<Employee> filteredEmployees = employees.stream() .collect(Collectors.toMap( // keyMapper: 定义如何从Employee对象中提取键 // 这里将firstName和lastName拼接作为键 employee -> employee.getFirstName() + employee.getLastName(), // valueMapper: 定义如何从Employee对象中提取值 // Function.identity() 表示Employee对象本身作为值 Function.identity(), // mergeFunction: 定义当两个键相同时如何合并值 // 比较两个Employee对象的日期,保留日期最新的那个 (existingEmployee, newEmployee) -> existingEmployee.getDate().isAfter(newEmployee.getDate()) ? existingEmployee : newEmployee )) .values(); // 获取Map中所有的值,即我们筛选后的Employee对象 // 打印结果 filteredEmployees.forEach(System.out::println); } }
代码解析
- employees.stream(): 创建一个Employee对象的流。
- .collect(Collectors.toMap(...)): 这是核心操作。Collectors.toMap有多个重载方法,这里我们使用的是接受三个参数的版本:
- keyMapper (employee -> employee.getFirstName() + employee.getLastName()): 这个函数负责从每个Employee对象中提取出用于作为Map键的部分。在这里,我们将firstName和lastName字符串拼接起来,形成一个唯一的员工标识符。
- 注意事项: 字符串拼接作为键简单易行,但在某些情况下可能存在性能问题或潜在的哈希冲突风险(尽管对于人名组合通常足够)。更健壮的方法是定义一个包含firstName和lastName的自定义类作为键,并正确实现其equals()和hashCode()方法。
- valueMapper (Function.identity()): 这个函数负责从Employee对象中提取出用于作为Map值的部分。Function.identity()是一个方便的静态方法,它表示将输入对象本身作为输出,即Employee对象本身将作为Map的值。
- mergeFunction ((existingEmployee, newEmployee) -> existingEmployee.getDate().isAfter(newEmployee.getDate()) ? existingEmployee : newEmployee): 这是解决键冲突的关键。当keyMapper生成相同的键时,toMap会调用这个函数来决定保留哪个值。
- existingEmployee:是Map中已经存在的值(即之前处理过的相同键的Employee对象)。
- newEmployee:是当前正在处理的、与existingEmployee具有相同键的Employee对象。
- 我们的逻辑是比较它们的date字段。如果existingEmployee的日期在newEmployee之后,则保留existingEmployee;否则,保留newEmployee。这确保了Map中最终存储的是具有最新日期的Employee记录。
- keyMapper (employee -> employee.getFirstName() + employee.getLastName()): 这个函数负责从每个Employee对象中提取出用于作为Map键的部分。在这里,我们将firstName和lastName字符串拼接起来,形成一个唯一的员工标识符。
- .values(): Collectors.toMap操作返回一个Map
。我们只需要最终筛选出来的Employee对象,因此调用.values()方法获取Map中所有值的Collection。
运行结果
执行上述代码,将得到以下输出:
Employee(firstName=John, lastName=Smith, salary=5.0, date=2022-11-01) Employee(firstName=Sara, lastName=Kim, salary=7.0, date=2022-07-01) Employee(firstName=Kelly, lastName=Jones, salary=12.0, date=2022-03-01)
这正是我们期望的结果,对于每个唯一的员工组合,都成功筛选出了日期最新的那条记录。
总结与注意事项
- Collectors.toMap的强大之处: 通过提供一个自定义的合并函数,Collectors.toMap可以非常灵活地处理键冲突,这使其成为根据特定条件从分组数据中选择唯一记录的理想工具。
- 灵活性: mergeFunction可以根据不同的业务需求进行调整。例如,如果你想保留薪资最高的记录,可以将比较逻辑改为existingEmployee.getSalary() > newEmployee.getSalary() ? existingEmployee : newEmployee。
- 键的生成: 确保键的生成方式能够准确地识别你想要分组的唯一实体。对于多字段组合键,字符串拼接是一种简单的方法,但对于复杂对象或性能敏感的场景,自定义键对象并正确实现equals()和hashCode()会是更好的选择。
- 替代方案: 另一种实现方式是先使用Collectors.groupingBy按多字段分组,得到Map
>,然后再对每个List 进行排序和选择。但对于本例这种直接选择一个“最佳”记录的场景,Collectors.toMap通常更简洁高效。
通过本教程,您应该已经掌握了如何使用Java Stream API结合Collectors.toMap,根据对象的多个字段进行分组,并从每个分组中筛选出符合特定条件的唯一记录。这种模式在数据处理和聚合中非常常见且实用。
文中关于的知识介绍,希望对你的学习有所帮助!若是受益匪浅,那就动动鼠标收藏这篇《Java多字段分组取最新记录技巧》文章吧,也可关注golang学习网公众号了解相关技术文章。

- 上一篇
- Jira隐藏滚动条技巧,优化管理界面体验

- 下一篇
- RealPlayer查看版本方法详解
查看更多
最新文章
-
- 文章 · java教程 | 20分钟前 |
- GitHubActions集成Qodana传参技巧
- 317浏览 收藏
-
- 文章 · java教程 | 43分钟前 |
- JavaFXMySQL登录问题解决方法
- 147浏览 收藏
-
- 文章 · java教程 | 48分钟前 |
- Java多线程编程技巧与实战方法
- 247浏览 收藏
-
- 文章 · java教程 | 1小时前 |
- Java容器化部署:Dockerfile编写详解
- 179浏览 收藏
-
- 文章 · java教程 | 1小时前 | SpringBoot 模块化设计 aop Spring框架 ioc
- Spring框架核心模块详解与应用
- 122浏览 收藏
-
- 文章 · java教程 | 2小时前 |
- Java货币处理最佳实践与技巧
- 347浏览 收藏
-
- 文章 · java教程 | 2小时前 |
- Java实现文件下载与断点续传教程
- 241浏览 收藏
-
- 文章 · java教程 | 2小时前 |
- SeleniumXPath精准提取网页文本技巧
- 160浏览 收藏
-
- 文章 · java教程 | 3小时前 |
- Java调用Google地图路线规划方法
- 291浏览 收藏
查看更多
课程推荐
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 514次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 499次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 484次学习
查看更多
AI推荐
-
- AI Mermaid流程图
- SEO AI Mermaid 流程图工具:基于 Mermaid 语法,AI 辅助,自然语言生成流程图,提升可视化创作效率,适用于开发者、产品经理、教育工作者。
- 391次使用
-
- 搜获客【笔记生成器】
- 搜获客笔记生成器,国内首个聚焦小红书医美垂类的AI文案工具。1500万爆款文案库,行业专属算法,助您高效创作合规、引流的医美笔记,提升运营效率,引爆小红书流量!
- 373次使用
-
- iTerms
- iTerms是一款专业的一站式法律AI工作台,提供AI合同审查、AI合同起草及AI法律问答服务。通过智能问答、深度思考与联网检索,助您高效检索法律法规与司法判例,告别传统模板,实现合同一键起草与在线编辑,大幅提升法律事务处理效率。
- 403次使用
-
- TokenPony
- TokenPony是讯盟科技旗下的AI大模型聚合API平台。通过统一接口接入DeepSeek、Kimi、Qwen等主流模型,支持1024K超长上下文,实现零配置、免部署、极速响应与高性价比的AI应用开发,助力专业用户轻松构建智能服务。
- 386次使用
-
- 迅捷AIPPT
- 迅捷AIPPT是一款高效AI智能PPT生成软件,一键智能生成精美演示文稿。内置海量专业模板、多样风格,支持自定义大纲,助您轻松制作高质量PPT,大幅节省时间。
- 380次使用
查看更多
相关文章
-
- 提升Java功能开发效率的有力工具:微服务架构
- 2023-10-06 501浏览
-
- 掌握Java海康SDK二次开发的必备技巧
- 2023-10-01 501浏览
-
- 如何使用java实现桶排序算法
- 2023-10-03 501浏览
-
- Java开发实战经验:如何优化开发逻辑
- 2023-10-31 501浏览
-
- 如何使用Java中的Math.max()方法比较两个数的大小?
- 2023-11-18 501浏览