java中comparator接口通过lambda等实现自定义排序,支持链式多级排序、null安全处理及逻辑封装。

Java 中通过 Comparator 函数式接口实现自定义排序,核心是提供一个比较逻辑(即两个对象谁大谁小),然后交给集合或数组的排序方法使用。它本质是一个接受两个参数、返回 int 的函数式接口,可以用 Lambda 表达式、方法引用或匿名内部类来实现,其中 Lambda 最简洁常用。
用 Lambda 表达式写一行比较逻辑
这是最直观的方式:直接在 sort() 或 sorted() 中传入 Lambda,形如 (a, b) -> ...。返回负数表示 a 在 b 前,正数表示 a 在 b 后,0 表示相等。
例如,对 List<string></string> 按长度升序排列:
Collections.sort(list, (s1, s2) -> s1.length() - s2.length());
注意:避免用 s1.length() - s2.length() 可能整数溢出(极少见但存在),更安全写法是用 Integer.compare(s1.length(), s2.length())。
链式调用实现多级排序
Comparator 提供了 thenComparing() 等默认方法,支持先按主字段排、再按次字段排,逻辑清晰且可读性强。
比如对用户列表先按年龄升序,年龄相同时按姓名字典序降序:
Comparator<user> cmp = Comparator.comparing(User::getAge)
.thenComparing(User::getName, Comparator.reverseOrder());
list.sort(cmp);</user>-
comparing()用于提取主排序字段(必须是可比较类型) -
thenComparing()支持传字段方法引用,也可传另一个Comparator -
reverseOrder()返回逆序比较器,无需手写(a,b) -> b.compareTo(a)
处理 null 值的安全写法
如果待排序对象中字段可能为 null,直接调用 compareTo() 会抛 NullPointerException。推荐用 Comparator.nullsFirst() 或 nullsLast() 包装。
例如按姓名排序,null 名字排最后:
list.sort(Comparator.comparing(User::getName,
Comparator.nullsLast(String::compareTo)));-
nullsFirst()把null当最小值,排最前 -
nullsLast()把null当最大值,排最后 - 包装的是字段比较器,不是整个
Comparator对象
复用与封装:把比较逻辑抽成静态方法
复杂或重复使用的排序逻辑建议封装为静态工具方法,提升可读性和复用性。
例如定义一个按“年龄倒序、姓名正序”的通用比较器:
public static Comparator<user> byAgeDescThenNameAsc() {
return Comparator.comparing(User::getAge, Comparator.reverseOrder())
.thenComparing(User::getName);
}</user>调用时直接:list.sort(byAgeDescThenNameAsc()); —— 语义明确,不散落业务代码中。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











