TreeMap 构造时必须传入 Comparator 才能自定义排序,之后无法更改;String Key 倒序用 Comparator.reverseOrder();自定义 Key 需处理 null 安全与不可变性,否则导致查找失败或结构损坏。

TreeMap 默认就按 Key 排序,不需要你手动排序;但想改排序规则,必须在构造时传入 Comparator,之后无法动态更换。
TreeMap 构造时传 Comparator 是唯一生效时机
很多人试图先 new 一个空 TreeMap,再调用某个方法“设置”比较器——没这回事。TreeMap 的比较逻辑在构造完成那一刻就锁死了,后续所有 put、get、keySet() 都依赖它。
- ✅ 正确:用
new TreeMap(Comparator.comparing(...))或自定义Comparator实现类 - ❌ 错误:
TreeMap map = new TreeMap(); map.setComparator(...)(根本不存在这个方法) - ⚠️ 注意:
TreeMap(Map)构造函数不会继承原 Map 的顺序逻辑,它会用自然顺序(或默认Comparator),除非你显式传入带比较器的构造器
String 类型 Key 用 Comparator.reverseOrder() 就够了
如果 Key 是 String,又想倒序排列,别手写 compare 方法——JDK 8+ 提供了现成的静态工厂方法,简洁且无装箱开销。
- 正序(默认):
new TreeMap()或new TreeMap(Comparator.naturalOrder()) - 倒序:
new TreeMap(Comparator.reverseOrder()) - 忽略大小写倒序:
new TreeMap(String.CASE_INSENSITIVE_ORDER.reversed()) - ⚠️ 别写
new TreeMap((a, b) -> b.compareTo(a))—— 多余,还容易空指针(没判 null)
自定义对象作 Key 必须处理 null 安全和 equals 一致性
用自定义类当 Key 时,Comparator 的行为必须和 equals()、hashCode() 逻辑不冲突,否则 containsKey() 可能返回 false,即使 key 看起来“相等”。
立即学习“Java免费学习笔记(深入)”;
- ❌ 危险写法:
Comparator.comparing(User::getName),但 User.name 可能为 null → 抛NullPointerException - ✅ 安全写法:
Comparator.comparing(User::getName, Comparator.nullsLast(String::compareTo)) - ⚠️ 更关键的是:如果两个 User 对象
name相同但id不同,它们在TreeMap中是否算同一个 key?取决于你的Comparator是否把id作为次级排序字段。如果不加,put可能覆盖掉旧值,而你以为是新增 - 性能提示:避免在
compare()里做 IO、数据库查询或复杂计算——每次put/get都会调用它,树高 O(log n),但常数项会被放大
TreeMap 的 keySet() / entrySet() 返回的是“实时视图”,不是快照
有人以为遍历 keySet() 时删元素没问题,其实和 HashMap 一样,直接删会触发 ConcurrentModificationException,除非用迭代器的 remove() 方法。
- ✅ 安全删除:
Iterator<map.entry integer>> it = map.entrySet().iterator(); while (it.hasNext()) { if (someCondition) it.remove(); }</map.entry> - ❌ 危险操作:
for (String k : map.keySet()) { if (k.startsWith("tmp")) map.remove(k); }→ 运行时报错 - ⚠️ 特别注意:如果你的
Comparator依赖对象内部可变状态(比如某字段 later 被修改),那么该对象插入后又被修改,TreeMap 的结构可能损坏——get()找不到、size()异常、甚至死循环。Key 对象应当尽量不可变(immutable)
最常被忽略的其实是 Key 的可变性问题:Comparator 没写错、null 处理也到位,但某个 User 对象插入后改了 name,整个 TreeMap 就“失序”了——它不会自动重排,后续操作结果不可预测。










