collections.sort() 实现自定义排序需确保列表可修改,支持comparable(自然排序)或comparator(灵活排序),注意null处理、类型一致、避免溢出与浮点比较陷阱。

用 Collections.sort() 实现自定义排序,关键不是写得多 fancy,而是逻辑清晰、覆盖边界、不抛异常。它只接受 List,原地修改,不生成新集合;支持两种路径:让元素自己会比(Comparable),或你告诉它怎么比(Comparator)。
自然排序:对象自己定义“谁大谁小”
当类实现了 Comparable 接口,并重写了 compareTo() 方法,就具备了默认排序能力。调用 Collections.sort(list) 就能直接升序排。
-
内置类型都已实现:
String按字典序、Integer按数值、LocalDate按时间先后,开箱即用 -
自定义类需主动实现:比如
Student想默认按学号排,就在compareTo中写return Integer.compare(this.id, other.id) -
注意 null 和类型一致性:列表里不能混装
String和Integer,否则运行时报ClassCastException;含null元素时,compareTo必须显式处理,否则抛NullPointerException
Comparator 自定义:不改类也能灵活排序
这是更常用、更推荐的方式,尤其适合同一类有多种排序需求(如按年龄、按姓名、先部门再薪资),或无法修改原始类的情况。
-
Lambda 表达式最简洁:比如字符串按长度升序:
(a, b) -> Integer.compare(a.length(), b.length());避免直接写a.length() - b.length(),防止整数溢出 -
链式构造更清晰:多字段排序用
comparing+thenComparing,例如按“部门→年龄降序→姓名”:Comparator.comparing(Employee::getDept).thenComparing(Employee::getAge, Comparator.reverseOrder()).thenComparing(Employee::getName) -
空值必须显式处理:字段可能为
null时,用nullsLast(Comparator.naturalOrder())或nullsFirst明确位置,否则运行时报错
常见陷阱与应对要点
看似简单,但几个细节一疏忽就出问题:
-
列表必须可修改:
Arrays.asList()返回的是固定大小列表,Collections.unmodifiableList()更是只读的——传给sort()会直接抛UnsupportedOperationException;确保用new ArrayList(...)或其他支持set()的实现 -
浮点数别用 == 比较:
Double或Float字段排序时,用Double.compare(a, b),而不是a - b或a == b -
忽略大小写要用标准方法:字符串排序不区分大小写,优先用
String::compareToIgnoreCase,而不是先转小写再比——后者在某些 Unicode 场景下结果不准
降序与逆序的写法选择
需要倒着排,有几种等效但语义不同的写法:
-
单字段降序:用
Comparator.comparingInt(Person::getAge).reversed(),语义明确、可读性强 -
手动翻转返回值:Lambda 中写
(a, b) -> Integer.compare(b.getAge(), a.getAge()),直观但容易看反 -
全局逆序:
Collections.reverseOrder()可作为 Comparator 传入,适用于简单类型,如Collections.sort(numbers, Collections.reverseOrder())











