怎么用 Comparator 去重
在 Java 里,Comparator 本身不能“直接去重”,但可以和 Set / Stream 配合,实现“按某种规则去重”。下面按常见场景给你讲清楚,并附示例代码。
一、核心思路
- 去重本质:判断“哪些元素算相同”
- Comparator 的作用:定义“相同”的规则
- 去重工具:
TreeSet(Comparator)Stream.distinct()❌(不能用 Comparator)Stream.collect(Collectors.toMap / groupingBy)✅
二、用 TreeSet + Comparator 去重(最常用)
示例:按某个字段去重
class User {
int id;
String name;
User(int id, String name) {
this.id = id;
this.name = name;
}
}
按 id 去重
List list = List.of(
new User(1, "A"),
new User(1, "B"),
new User(2, "C")
);
Set set = new TreeSet<>(
Comparator.comparingInt(User::getId)
);
set.addAll(list);
System.out.println(set);
✅ 结果:只保留一个 id=1 的元素
⚠️ 注意
TreeSet认为:compare(a, b) == 0 → a 和 b 相同- 即使 equals 返回 false,也会被去重
三、多个字段去重
Set set = new TreeSet<>(
Comparator.comparing(User::getName)
.thenComparing(User::getId)
);
四、用 Stream + Comparator 去重(推荐写法)
1️⃣ 用 Collectors.toMap
List result = list.stream()
.collect(Collectors.toMap(
User::getId, // 去重 key
u -> u, // 保留 value
(a, b) -> a // 冲突时保留谁
))
.values()
.stream()
.toList();
✅ 可读性好
✅ 不依赖 equals / hashCode
2️⃣ 用 Stream.distinct()(❌ 不能用 Comparator)
// ❌ 错误示例
list.stream().distinct(comparator); // 不存在
distinct() 只能依赖:
equals()hashCode()
五、如果对象没有 Comparator,怎么办?
方案 1:自定义 Comparator
Comparator byId = Comparator.comparingInt(User::getId);
方案 2:重写 equals / hashCode(不推荐混用)
@Override
public boolean equals(Object o) {
return o instanceof User u && u.id == this.id;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
然后:
Set set = new HashSet<>(list);
⚠️ Comparator 和 equals 不一致时,逻辑会很混乱
六、总结对照表
| 方式 | 是否用 Comparator | 是否推荐 |
|---|---|---|
| TreeSet + Comparator | ✅ | ✅ |
| Stream + toMap | ❌ | ✅✅ |
| Stream.distinct | ❌ | ❌ |
| HashSet + equals | ❌ | ⚠️ |
✅ 推荐结论
去重 ≠ Comparator
Comparator 用来定义“怎么算相同”
TreeSet / Stream 用来真正去重
如果你有具体场景(比如去重 List、Map、JSON、数据库结果),可以直接贴代码,我可以帮你写最优解。