HashSet 与 Stream API 可协同实现多字段去重:用 HashSet 记录已见的字段组合(如 name+"|"+email+"|"+phone),在 filter 中通过 seen.add(key) 判断首次出现,保留唯一项,时间复杂度 O(n),需防 null 和线程安全。

HashSet 和 Stream API 本身不直接“结合”做多字段去重,但可以协同使用:用 HashSet 作为状态容器辅助 Stream 的 filter() 操作,实现基于多个字段组合的去重逻辑。
核心思路:用 HashSet 记录已见过的字段组合
Stream 的 distinct() 只能按对象整体去重(依赖 equals/hashCode),无法直接支持“按 name+email+phone 去重”。这时需要手动控制“是否重复”的判断逻辑——HashSet 就是轻量、高效的状态记录工具。
- 定义一个 Set
(或 Set )来存已出现过的多字段标识,比如 name+"|"+email+"|"+phone - 在 filter 中调用 seen.add(key):add() 返回 true 表示首次插入,即该组合未出现过,保留;返回 false 则跳过
- 注意:seen 必须是外部定义的可变集合(不能在 lambda 内新建),且需保证线程安全(单线程场景下无需同步)
典型写法(推荐,简洁可靠)
```java
Set
List
.filter(u -> seen.add(u.getName() + "|" + u.getEmail() + "|" + u.getPhone()))
.collect(Collectors.toList());
```
- 分隔符(如 "|")建议选用数据中不会出现的字符,避免 "A|B" + "C" 和 "A" + "|BC" 误判为相同
- 若字段可能为 null,需先用 Objects.toString(u.getName(), "") 防 NPE
- 该方式保持原始顺序,且只遍历一次,时间复杂度 O(n)
替代方案:用 Collectors.toMap(更函数式,但稍重)
如果不想用外部变量,可用 toMap 按多字段生成 key,自动覆盖重复项:
- ```java
ListuniqueUsers = users.stream()
.collect(Collectors.toMap(
u -> u.getName() + "|" + u.getEmail() + "|" + u.getPhone(),
Function.identity(),
(u1, u2) -> u1 // 冲突时保留第一个
)).values().stream().collect(Collectors.toList());
``` - 优点:无副作用,纯函数风格;缺点:多一次遍历 + 构建 Map 开销,内存略高
为什么不直接 new HashSet(users)?
因为 HashSet 的去重依赖 User 类的 hashCode() 和 equals()。若这两个方法没按 name+email+phone 实现,就无法达成多字段去重效果——它只会按默认引用或你已定义的其他逻辑比较,和目标无关。
所以关键不在“用不用 HashSet”,而在于“怎么用”:把它当作临时状态缓存,配合 Stream 的 filter 才真正解决多字段场景。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











