TreeSet基于TreeMap红黑树实现,按自然顺序或Comparator排序,时间复杂度O(log n),要求Comparable/Comparator逻辑一致且处理null需显式指定。

TreeSet 默认按自然顺序排序,本质是基于 TreeMap 的红黑树实现
TreeSet 本身不存储元素,它只是 TreeMap 的一个包装:内部用 TreeMap 的 key 存元素,value 固定为 PRESENT(一个空的 Object)。所以 TreeSet 的排序逻辑完全继承自 TreeMap —— 底层是左倾红黑树,插入、删除、查找都是 O(log n)。
这意味着:只要元素实现了 Comparable 接口(比如 Integer、String),或者你传入了 Comparator,TreeSet 就能自动维护有序性。它不依赖插入顺序,也不做额外排序操作。
自定义排序必须确保 Comparator 或 Comparable 逻辑严格一致
常见错误是 compareTo() 或 compare() 返回 0 的条件和 equals() 不一致,导致集合行为异常——比如两个“逻辑相等”但 equals() 返回 false 的对象,可能同时存在于 TreeSet 中;反之,若 compareTo() 总返回 0,所有元素会被当成同一个 key,只保留一个。
- 必须满足自反性:
a.compareTo(a) == 0 - 必须满足传递性:若
a.compareTo(b) > 0且b.compareTo(c) > 0,则a.compareTo(c) > 0 - 若用
Comparator,建议用Comparator.nullsFirst()或Comparator.nullsLast()显式处理 null,避免NullPointerException
例如:
立即学习“Java免费学习笔记(深入)”;
Setset = new TreeSet<>(Comparator.nullsLast(String::compareToIgnoreCase));
TreeSet 不允许 null 元素(除非显式传入支持 null 的 Comparator)
默认构造的 TreeSet 调用元素的 compareTo(),而 null.compareTo() 会直接抛 NullPointerException。这不是“不能存 null”,而是“默认比较器不处理 null”。
- 如果用
new TreeSet(Comparator.nullsFirst(Comparator.naturalOrder())),null 会被排在最前 - 如果用
new TreeSet(Comparator.nullsLast(Comparator.naturalOrder())),null 会被排在最后 - 一旦用了支持 null 的 Comparator,就不能再往里 add
null以外的、自身compareTo()不支持 null 的对象(比如Integer的compareTo()本身不接受 null)
遍历 TreeSet 得到的是已排序结果,但不要误以为它是“排序后的数组”
TreeSet 的迭代器返回的是红黑树中序遍历结果,天然有序。但它不是一次性排序后缓存,而是每次访问都走树结构。所以:
- 调用
toArray()得到的是有序数组,但这是拷贝操作,O(n) - 反复调用
first()/last()是 O(1),因为红黑树维护了最左/最右节点引用 - 用
subSet(from, to)等范围视图时,底层仍是同一棵树,修改视图会影响原 set
真正容易被忽略的一点:TreeSet 的“有序”是逻辑有序,不是插入有序;它的线程不安全,多线程写入必须手动同步,否则可能破坏红黑树结构,引发 ConcurrentModificationException 或更隐蔽的错乱。










