Java中Collections.sort()排序需确保稳定、准确、可读、可复用,核心是合理使用Comparator链式调用、空值安全处理、防溢出防NPE,并将复用逻辑抽为静态常量。

Java 中用 Collections.sort() 排序,核心不是“会不会调用”,而是怎么让排序逻辑稳、准、可读、可复用。它原地修改 List,不新建集合,性能可靠(基于 TimSort),但用错方式容易出 NPE、溢出或语义偏差。
多字段组合排序:链式构建比嵌套 if 更清晰
业务中常见“先按部门升序 → 同部门按薪资降序 → 再按姓名字典序”这类需求。推荐用 Comparator.comparing() 链式调用:
-
Comparator.comparing(Person::getDept)控制第一优先级 -
.thenComparing(Person::getSalary, Comparator.reverseOrder())实现第二字段降序 -
.thenComparing(Person::getName, String.CASE_INSENSITIVE_ORDER)第三字段忽略大小写
这种写法天然支持 null 值默认处理(null 排最前),如需调整,可在任一环节包裹 nullsLast() 或 nullsFirst()。
空值安全必须显式声明
数据库或接口返回的数据常含 null 字段,比如 user.getPhone() 可能为 null。直接用于比较会抛 NullPointerException。
立即学习“Java免费学习笔记(深入)”;
- 字段本身可能为 null:用
Comparator.nullsLast(Comparator.comparing(User::getPhone)) - 字段方法调用可能空指针:改用安全取值,例如
Comparator.comparing(u -> u.getPhone() != null ? u.getPhone().length() : 0) - 字符串比较时,别用
u1.getName().compareTo(u2.getName()),改用Comparator.nullsLast(String::compareTo)
数值与字符串比较要防坑
看似简单的比较,细节决定成败:
- 别写
a.getAge() - b.getAge():int 溢出时结果反转,应统一用Integer.compare(a.getAge(), b.getAge()) - 浮点数避免
==或减法,用Double.compare(a.getScore(), b.getScore()) - 字符串忽略大小写,优先用
String.CASE_INSENSITIVE_ORDER::compare,而非手动转小写再比
复用与解耦:把排序逻辑抽成静态常量
同一排序规则在多个 Service 或测试中重复出现,硬编码 Lambda 会导致维护困难。
- 定义公共比较器:
public static final Comparator<User> BY_AGE_THEN_NAME = Comparator.comparing(User::getAge).thenComparing(User::getName); - 在业务代码中直接复用:
Collections.sort(users, UserComparators.BY_AGE_THEN_NAME); - 单元测试可单独验证该比较器行为,无需启动整个上下文
不复杂但容易忽略


















