Collections.sort 性能取决于 Comparator 是否规范:需避免溢出与 null 异常,用 Integer.compare 等工具方法;禁止 I/O、状态修改;保证纯函数性;善用标准 API 如 comparing 和 thenComparing。

Collections.sort 的性能不取决于你换什么算法,而取决于 Comparator 写得是否“守规矩”。它底层用的是 TimSort,这个算法对比较器的稳定性、纯度和边界处理非常敏感——写错一点,轻则变慢,重则抛 IllegalArgumentException 或排错。
避免整数溢出与 null 异常
直接用 a - b 计算差值容易溢出(比如 Integer.MIN_VALUE - 1 变成正数),导致排序逻辑反转。同样,字段为 null 时调用 str1.compareTo(str2) 会直接 NPE。
- 用 Integer.compare(a, b)、Long.compare() 等工具方法替代减法
- 字段可能为空时,优先用 Comparator.nullsFirst(Comparator.comparing(...)) 或 Objects.compare(x, y, nullsLast(naturalOrder()))
- 测试必须覆盖 null 值、相同 key 多个对象、极值(如 MAX/MIN_VALUE)等边界情况
减少 compare 方法的执行开销
TimSort 在预处理阶段会对每个 run 内部做插入排序,若 compare 本身很重(比如每次调用都解析 JSON、查数据库、或遍历深层对象),这部分开销会被反复放大。
- 禁止在 compare 中做 I/O、加锁、远程调用、反射取值
- 把计算结果缓存到对象字段里,比如提前算好 normalizedKey 或 sortCode
- 优先用 Comparator.comparing(User::getPrecomputedAge),而不是 (u1, u2) -> computeAge(u1) - computeAge(u2)
- 小列表(size < 16)完全走插入排序,此时 compare 的常数因子影响更明显
保证比较逻辑的确定性与一致性
TimSort 归并阶段会跨 run 比较元素(比如判断 runA 最大值是否 ≤ runB 最小值),如果 compare 结果随时间、线程或状态变化,归并决策就会错乱,甚至破坏稳定性或卡死。
- Comparator 必须是纯函数:相同输入,永远返回相同输出
- 禁止在 compare 中修改对象、更新 volatile 以外的共享变量、读取系统时间或随机数
- 避免依赖未同步的外部状态(如静态计数器、缓存未加锁读取)
- 链式比较(thenComparing)时,每个子比较器都要独立满足 null 安全和确定性
善用标准写法,少写手写逻辑
手动写 lambda 或匿名类容易漏掉 null 判断、溢出处理或逻辑对称性;而标准 API 已内置这些防护。
- 升序用 comparing(Obj::getField),降序加 .reversed()
- 多级排序用 comparing(...).thenComparing(...).thenComparingInt(...)
- 字符串忽略大小写: comparing(Obj::getName, String.CASE_INSENSITIVE_ORDER)
- 避免方法引用带副作用,如 User::getComputedName() 若内部有懒加载或状态变更就不安全


















