
本文介绍如何利用 java 8 stream api 和 collectors.tomap 实现按指定字段(如 id)对对象列表去重,保留首次出现的元素,并返回新的唯一对象列表。
本文介绍如何利用 java 8 stream api 和 collectors.tomap 实现按指定字段(如 id)对对象列表去重,保留首次出现的元素,并返回新的唯一对象列表。
在实际开发中,尤其是处理数据库 JOIN 查询结果时,常因关联关系导致同一主实体(如 Account)被重复加载多次——例如多个时间戳或关联子记录引发的“一拖多”数据膨胀。此时,若只需保留每个唯一 ID 对应的首个 Account 实例,直接使用 distinct() 并不可行(因其依赖 equals()/hashCode() 全字段比较),而基于业务主键(如 id)去重才是合理方案。
推荐采用 Collectors.toMap() 配合 Stream 流式处理,其核心逻辑是:以 id 为 key、Account 对象为 value 构建 Map,在遇到重复 key 时通过自定义合并函数决定保留策略。以下是完整实现:
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
List<account> uniqueAccounts = accountList
.stream()
.collect(Collectors.toMap(
Account::getId, // key: 使用 getId() 提取唯一标识
Function.identity(), // value: 直接保留原 Account 对象
(account1, account2) -> account1 // 冲突时保留第一个(即先出现者)
))
.values()
.stream()
.collect(Collectors.toList());</account>
✅ 关键说明:
- Function.identity() 是 t -> t 的简洁写法,确保 value 为原始对象;
- 合并函数 (account1, account2) -> account1 明确保留首次映射的 Account(即流中靠前的元素);若需保留最后一条,可改为 (account1, account2) -> account2;
- 最终调用 .values().stream().collect(...) 将 Map 的 value 集合转回 List
。
⚠️ 注意事项:
- Account 类必须正确实现 getId() 方法(返回 String 类型非空 ID);
- 若 accountList 为 null,需提前判空,避免 NullPointerException;
- 该方法不修改原列表,符合函数式编程的不可变原则;
- 性能上为 O(n),优于嵌套循环去重,且代码简洁可读。
综上,基于 toMap 的去重方案兼顾语义清晰性、扩展性与性能,是 Java Stream 处理“按字段去重”场景的标准实践。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











