Comparator 怎么处理相等
Comparator 里“相等”的处理,核心只有一句话:compare(a, b) == 0 就表示“相等 / 等价”。
下面分几种常见情况说明。
1. 基本规则(最重要)
Comparator c;
c.compare(a, b) < 0→ a 排在 b 前面c.compare(a, b) == 0→ a 和 b 被认为是“相等”c.compare(a, b) > 0→ a 排在 b 后面
⚠️ 注意:compare == 0 只表示“排序等价”,不要求 a.equals(b) 为 true。
2. 只按一个字段比较(常见)
Comparator byAge = Comparator.comparing(Person::getAge);
- 年龄相同 →
compare == 0 - 排序时顺序不确定(可能保持原顺序 / 不稳定)
3. 处理“相等”时再按其他字段排(推荐)
如果你不希望“相等”真的相等,而是想继续区分:
Comparator cmp = Comparator
.comparing(Person::getAge)
.thenComparing(Person::getName);
✅ 这样:
- 年龄相同 → 再按名字排
- 几乎不会出现
compare == 0的情况
4. 想“完全相等”才返回 0(业务相等)
Comparator cmp = (p1, p2) -> {
if (p1.getId().equals(p2.getId())) {
return 0;
}
return p1.getAge() - p2.getAge();
};
✅ 表示:
- id 相同 → 完全相等
- 否则按年龄排
5. 排序稳定性(很多人会忽略)
List.sort()/Collections.sort():稳定排序- 如果
compare(a, b) == 0,原来在前面的仍然在前面
// 稳定排序下
compare == 0 → 不交换顺序
6. TreeSet / TreeMap 中的“相等陷阱”
TreeSet set = new TreeSet<>(
Comparator.comparing(Person::getAge)
);
⚠️ 问题:
- 年龄相同 →
compare == 0 - TreeSet 认为它们是同一个元素
- 后一个会被丢弃(即使
equals不一样)
✅ 正确做法:
Comparator cmp = Comparator
.comparing(Person::getAge)
.thenComparing(Person::getId);
7. 常见错误总结
❌ 忘记处理相等情况
❌ 用 Comparator 当 equals 用
❌ 在 TreeSet 里只比较部分字段
✅ 经验法则:
如果
compare == 0,就当它们是“同一个东西”
8. 一句话总结
Comparator 中:
compare(a,b) == 0= 相等
如果你不想“相等”,就继续thenComparing
如果你有具体场景(排序 / TreeSet / 自定义对象 / 性能问题),可以直接贴代码,我可以帮你改到最优。