JDK 1.8 为 Comparator 接口引入了默认方法,最常用的是 reversed() 和 thenComparing() 系列,适合在不创建新类的情况下实现链式排序逻辑。注意这是 JDK 1.8 版本引入的特性,而非 1.8 之后的版本。
先说结论:默认方法让排序规则组合更灵活,主要解决多条件排序和逆序需求,无需额外工具类。
- 适合:集合排序需要动态组合规则的场景,如先按年龄再按姓名排序。
- 核心方法:reversed() 用于反转顺序,thenComparing() 及其变体用于追加条件。
- 建议:配合 Lambda 表达式使用,代码更简洁,但必须注意空指针风险,建议配合 nullsFirst/nullsLast 使用。
新增默认方法列表
除了常见的 reversed() 和 thenComparing(Comparator),JDK 1.8 还针对基本类型提供了优化方法,避免装箱开销:
- reversed():返回一个逆序比较器。
- thenComparing(Comparator):追加另一个比较器。
- thenComparingInt(ToIntFunction):追加 int 类型键的比较,性能更好。
- thenComparingLong(ToLongFunction):追加 long 类型键的比较。
- thenComparingDouble(ToDoubleFunction):追加 double 类型键的比较。
完整代码示例
以下是一个完整可运行的 Java 类示例,展示了多条件排序及基本类型优化方法的使用:
import java.util.*;
import java.util.Comparator;
public class ComparatorDemo {
static class Person {
String name;
int age;
long salary;
public Person(String name, int age, long salary) {
this.name = name; this.age = age; this.salary = salary;
}
public String toString() { return name + "-" + age + "-" + salary; }
public int getAge() { return age; }
public long getSalary() { return salary; }
}
public static void main(String[] args) {
List<Person> list = Arrays.asList(
new Person("Alice", 25, 10000),
new Person("Bob", 25, 8000),
new Person("Charlie", 30, 12000)
);
// 多条件排序:先按年龄升序,年龄相同按薪水降序
list.sort(Comparator.comparingInt(Person::getAge)
.thenComparing(Comparator.comparingLong(Person::getSalary).reversed()));
list.forEach(System.out::println);
}
}空值处理最佳实践
默认方法本身不处理 null 值。如果集合元素或比较字段可能为 null,需配合静态方法 nullsFirst 或 nullsLast 使用,否则可能抛出 NullPointerException。
// 安全排序:null 值排在前面,再按年龄排序
list.sort(Comparator.nullsFirst(Comparator.comparingInt(Person::getAge)));
// 字段可能为 null 的情况
list.sort(Comparator.comparing(Person::getName, Comparator.nullsLast(Comparator.naturalOrder())));怎么验证是否生效
1. 运行测试:编写一个 main 方法,创建包含重复字段值的对象列表。
2. 打印结果:排序后遍历打印列表,观察顺序是否符合预期(如降序或第二条件生效)。
3. 检查日志:如果有自定义比较逻辑,可在比较方法中打日志,确认 thenComparing 是否在第一个条件相等时被调用。
常见坑
1. 空指针异常:默认方法本身不处理 null 值。如果集合元素或比较字段可能为 null,需配合静态方法 nullsFirst 或 nullsLast 使用,否则可能抛出 NullPointerException。
2. 静态与默认混淆:comparing、naturalOrder 等是静态方法,需要通过类名调用;reversed、thenComparing 是默认方法,需要通过实例调用。混淆会导致编译错误。
3. 基本类型支持:Comparator 主要针对对象。如果是 int[] 等基本类型数组,不能直接使用 List.sort,需先装箱或使用 Arrays.sort 的特定重载。
4. 版本兼容性:确保项目 JDK 版本为 1.8 或更高,否则无法识别 default 关键字和相应方法。