TreeMap 默认按键自然顺序排序,要求键实现Comparable或传入Comparator,否则抛ClassCastException;不支持null键(无参构造时),需用Comparator显式支持;定制排序推荐lambda表达式,注意comparator的三性及稳定性。

TreeMap 默认按键自然顺序排序,但必须确保键类型实现 Comparable 或传入 Comparator,否则运行时抛 ClassCastException。
为什么 new TreeMap() 有时会直接报错?
常见于键是自定义类(如 User、Point)且未实现 Comparable,或用了 null 键(TreeMap 不允许 null 键,除非显式传入支持 null 的 Comparator)。
错误信息典型为:java.lang.ClassCastException: class X cannot be cast to class java.lang.Comparable。
- 检查键类是否实现了
Comparable,并正确重写compareTo() - 若无法修改键类(如第三方类),必须在构造时传入
Comparator - 避免在无参构造的
TreeMap中插入null键 —— 这会立即触发NullPointerException
如何用 Comparator 定制排序逻辑?
适用于键不可修改、需多维度排序、或按非自然顺序(如字符串忽略大小写、倒序)等场景。
推荐使用 lambda 表达式,简洁且类型安全:
TreeMap<string integer> map = new TreeMap((s1, s2) ->
s1.toLowerCase().compareTo(s2.toLowerCase())
);
map.put("Apple", 1);
map.put("banana", 2);
// 遍历时按键 "Apple" <ul>
<li>Comparator 必须满足「自反性、对称性、传递性」,否则 <code>TreeMap</code> 行为未定义(可能漏 entry、查找失败)</li>
<li>不要在 comparator 中调用 <code>map.get()</code> 或其他可能触发树操作的方法,易引发 <code>ConcurrentModificationException</code>
</li>
<li>若 comparator 返回 0,视为两键相等 → 后插入的 value 会覆盖前者</li>
</ul>
<h3>TreeMap 的 keySet() / entrySet() 是有序的,但迭代器不支持快速失败保护</h3>
<p><code>TreeMap</code> 的 <code>keySet()</code> 和 <code>entrySet()</code> 返回的是视图(view),其迭代器是 fail-fast 的 —— 但仅对结构性修改(如 <code>put()</code>、<code>remove()</code>)敏感,对 value 修改无影响。</p>
<ul>
<li>遍历中调用 <code>map.remove(key)</code> 会触发 <code>ConcurrentModificationException</code>
</li>
<li>安全删除应使用迭代器的 <code>remove()</code> 方法:<code>it.remove()</code>
</li>
<li>若需边遍历边插入,改用 <code>forEach()</code> + 收集待操作 key 列表,再批量处理</li>
</ul>
<h3>性能与替代方案要注意什么?</h3>
<p><code>TreeMap</code> 是红黑树实现,<code>get/put/remove</code> 均为 <code>O(log n)</code>;而 <code>HashMap</code> 是 <code>O(1)</code> 平均。如果只是偶尔排序(如最后输出一次),用 <code>HashMap</code> + <code>TreeSet</code> 或 <code>sorted(entrySet())</code> 更轻量。</p>
<ul>
<li>频繁增删查 + 持续需要有序遍历 → <code>TreeMap</code> 合理</li>
<li>写多读少,且排序只用于最终展示 → 先用 <code>HashMap</code>,需要时转 <code>new TreeMap(map)</code>(注意:此操作是 <code>O(n log n)</code>)</li>
<li>Java 8+ 中,<code>ConcurrentSkipListMap</code> 提供线程安全的有序映射,但比 <code>TreeMap</code> 开销大,别只为“并发”盲目替换</li>
</ul>
<p>真正容易被忽略的是 comparator 的稳定性 —— 比如用对象字段排序时,字段值在插入后又被外部修改,会导致树结构错乱,后续 <code>get()</code> 可能找不到本该存在的键。</p></string>
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











