java中自定义排序应优先使用comparator,确保规则准确、边界安全、语义正确;collections.sort()就地排序,单字段用comparingint等防溢出,多字段链式调用,null值显式处理,浮点与时间排序需专用compare方法。

Java里用Collections.sort()做自定义排序,关键不是写得多炫,而是规则写得准、边界兜得住、业务语义对得上。它不返回新列表,直接改原List,适合大多数就地排序场景。
单字段排序:简洁优先,避开整数溢出
按字符串长度升序,别写 a.length() - b.length()——万一长度差超过 Integer.MAX_VALUE 就溢出变负数,排序错乱。正确写法是:
- 用
Integer.compare(a.length(), b.length()) - 或更推荐
Comparator.comparingInt(String::length),自动处理类型和空值逻辑 - 忽略大小写比较字符串?直接用
String::compareToIgnoreCase,比手写toLowerCase()安全又高效
多字段组合排序:链式调用,优先级清晰
比如“部门升序 → 年龄降序 → 姓名升序”,一行搞定:
Comparator.comparing(Employee::getDept).thenComparing(Employee::getAge, Comparator.reverseOrder()).thenComparing(Employee::getName)
某字段可能为 null?加一层 nullsLast(Comparator.naturalOrder()),空值统一排末尾,避免 NPE。
空值与类型安全:不能靠猜,得显式处理
字段可能为 null 是常态,别在 lambda 里直接调 a.getName().compareTo(...):
- 用
Comparator.nullsLast(Comparator.comparing(Person::getName)) - 浮点数比较不用
==或a - b,一律用Double.compare(a, b) - 时间字段排序?
Comparator.comparing(User::getCreateTime)天然支持,无需额外转换
什么时候该用 Comparable 而不是 Comparator?
只有一种天然、稳定、全局认同的顺序时才实现 Comparable,比如学号之于学生、订单号之于订单:
- 重写
compareTo()时仍要用Objects.compare()或Integer.compare(),别手算差值 - 同一类有多种排序需求(按年龄、按分数、按创建时间),必须用
Comparator,否则会污染领域模型 - 第三方类或不可修改类,只能靠
Comparator,这是它的核心价值
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











