treemap默认按键的compareto()排序,要求键实现comparable接口,否则需传入comparator,否则抛classcastexception;它只按键排序,不按值排序。

TreeMap 默认按键的 compareTo() 方法排序,前提是键实现了 Comparable 接口;否则必须显式传入 Comparator,否则运行时抛出 ClassCastException。
默认排序:键必须实现 Comparable
TreeMap 不是“自动按值排序”,它只关心键(K)的顺序。如果构造时没传 Comparator,它会尝试把键强转为 Comparable 并调用 compareTo():
- 整数、字符串等 JDK 内置类型天然支持,比如
TreeMap<integer string></integer>插入3, 1, 2→ 遍历输出键为1, 2, 3 - 自定义类(如
Student)若未实现Comparable,直接 newTreeMap()后put(new Student(...), ...)会立即抛ClassCastException -
compareTo()返回负数、0、正数分别表示“小于”“等于”“大于”,必须满足自反性、传递性、对称性,否则排序行为不可预测
自定义排序:用 Comparator 覆盖默认逻辑
两种常用方式,推荐 Lambda(简洁)或匿名内部类(需复用时):
TreeMap<String, Integer> byLength = new TreeMap<>((s1, s2) -> Integer.compare(s1.length(), s2.length()));
byLength.put("hi", 1);
byLength.put("hello", 2);
byLength.put("a", 3);
// 输出顺序:a → hi → hello(按字符串长度升序)
- 传入
Comparator后,Comparable接口是否实现完全无关,TreeMap 只调用你提供的比较逻辑 - 若需多级排序(如先按年龄升序,年龄相同时按姓名降序),Lambda 中写清楚判断链:
(s1, s2) -> { int c1 = Integer.compare(s1.age, s2.age); return c1 != 0 ? c1 : s2.name.compareTo(s1.name); } - 注意:Comparator 的返回值语义必须和自然顺序一致——返回负数表示“s1 应排在 s2 前面”,别反着写
常见踩坑:null 键、重复键、性能盲区
TreeMap 对 null 键零容忍(除非 Comparator 显式允许),且排序错误常表现为“看似有序但漏元素”或“死循环”:
立即学习“Java免费学习笔记(深入)”;
-
TreeMap不允许null作为键(put(null, "x")直接抛NullPointerException),Comparator里也不能对null调用方法,需提前判空 - 如果
compareTo()或compare()总返回 0(比如忘了写return),所有键会被视为“相等”,后插入的值不断覆盖前一个,最终只剩一个 entry - 红黑树的
O(log n)查找/插入虽稳定,但比HashMap的O(1)慢不少;频繁增删+只需遍历一次的场景,不如先用HashMap存好再TreeSet或sorted(list)临时排序
范围查询:subMap、headMap、tailMap 的边界陷阱
这些方法返回的是原 TreeMap 的**视图(live view)**,修改子映射会影响原 map,且边界是“半开区间”:
TreeMap<Integer, String> m = new TreeMap<>(); m.put(1, "a"); m.put(3, "c"); m.put(5, "e"); m.put(7, "g"); SortedMap<Integer, String> sub = m.subMap(3, 7); // 注意:包含 3,不包含 7 System.out.println(sub.keySet()); // [3, 5] sub.put(4, "d"); // ✅ 成功,m 中也多了 4→"d" System.out.println(m.containsKey(4)); // true
-
subMap(fromKey, toKey):≥fromKey且 toKey;headMap(toKey)是 toKey;tailMap(fromKey)是 ≥fromKey - 如果
fromKey不存在,tailMap会从第一个 ≥ 它的键开始;同理floorKey()和ceilingKey()才是“找最近存在的键”的正确工具 - 试图用不存在的键调用
subMap(10, 20)不报错,但返回空SortedMap—— 很容易被忽略导致逻辑空转
真正决定排序行为的从来不是 TreeMap 本身,而是你给它的键类型或 Comparator;一旦比较逻辑有歧义(比如浮点数用 == 判等、字符串忽略大小写但没用 String.CASE_INSENSITIVE_ORDER),后续所有有序操作都会悄然失效。










