| 维度 | Comparable<T> | Comparator<T> |
|---|---|---|
| 包位置 | java.lang | java.util |
| 核心方法 | int compareTo(T o) | int compare(T o1, T o2) |
| 设计意图 | 内部排序:类自我定义「自然顺序」 | 外部策略:分离比较逻辑,支持多种排序 |
| 实现方式 | 类自身 implements Comparable | 独立类 implements Comparator |
| 适用场景 | 单一、固有、通用的排序规则 | 多维度、临时、第三方类无法修改 |
| 集成集合 | TreeSet/TreeMap 键直接可用 | 需显式传入构造器/方法 |
public class Person implements Comparable<Person> {
String name; int age;
@Override
public int compareTo(Person other) {
// 按姓名自然顺序(字典序)
return this.name.compareTo(other.name);
}
}
// 直接使用
List<Person> list = ...;
Collections.sort(list); // 无需指定比较器
TreeSet<Person> set = new TreeSet<>(list); // 自动按 compareTo 排序去重
sgn(x.compareTo(y)) == -sgn(y.compareTo(x))(反对称)(x.compareTo(y) > 0 && y.compareTo(z) > 0) → x.compareTo(z) > 0(x.compareTo(y) == 0) == x.equals(y),违反会导致 TreeSet/TreeMap 行为异常(如无法找到元素)// 年龄升序比较器
public class AgeAscComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return Integer.compare(p1.getAge(), p2.getAge()); // 空安全、无溢出
}
}
// 年龄降序比较器(复用升序逻辑)
public class AgeDescComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return AgeAscComparator.INSTANCE.compare(p2, p1); // 反转
}
}
// 使用
Collections.sort(list, new AgeAscComparator());
list.sort(Comparator.comparing(Person::getAge).reversed()); // Java 8 链式 API
// 复合排序:先按年龄升序,年龄相同再按姓名降序
Comparator<Person> composite = Comparator
.comparing(Person::getAge)
.thenComparing(Person::getName, Comparator.reverseOrder());
// 空值友好排序:null 排最后
Comparator<Person> nullSafe = Comparator
.comparing(Person::getName, Comparator.nullsLast(String::compareTo));
// 分组排序:按部门分组,组内按薪资降序
Map<String, List<Employee>> byDept = employees.stream()
.collect(Collectors.groupingBy(Employee::getDept,
Collectors.collectingAndThen(
Collectors.toList(),
list -> list.stream()
.sorted(Comparator.comparing(Employee::getSalary).reversed())
.collect(Collectors.toList())
)
));
List<Person> people = Arrays.asList(
new Person("ccc", 20), new Person("AAA", 30),
new Person("bbb", 10), new Person("ddd", 40)
);
// 1. 自然顺序(姓名字典序,区分大小写)
Collections.sort(people);
// [AAA-30, bbb-10, ccc-20, ddd-40]
// 2. 年龄升序(外部比较器)
Collections.sort(people, new AgeAscComparator());
// [bbb-10, ccc-20, AAA-30, ddd-40]
// 3. 年龄降序
Collections.sort(people, new AgeDescComparator());
// [ddd-40, AAA-30, ccc-20, bbb-10]
// 4. 忽略大小写姓名排序(Lambda 临时比较器)
people.sort(Comparator.comparing(Person::getName, String.CASE_INSENSITIVE_ORDER));
// [AAA-30, bbb-10, ccc-20, ddd-40]
Comparable 定义唯一自然顺序(如 ID、姓名、时间)Comparator 或用 LambdaInteger.compare(a, b) / Long.compare / Double.compare:无溢出风险,比 a - b 更安全Comparator.nullsFirst/Last:显式处理 null,避免 NPEComparable 是「我是谁」(内在秩序),Comparator 是「怎么看我」(外在视角)。掌握 Java 8 链式 API 与 复合排序,能用极简代码表达复杂排序需求。设计类时,谨慎实现 Comparable,确保与 equals 一致;使用时,优先 Comparator 组合,保持领域模型纯净。