目录
- 核心概念:
Comparator是什么? - 为什么需要
Comparator? (与Comparable的对比) - 如何使用
Comparator?- 传统匿名内部类方式
- Java 8+ 的 Lambda 表达式 (推荐)
- Java 8+ 的
Comparator静态方法链式调用 (最现代、最推荐)
- 实战案例:对复杂对象列表进行排序
Comparator常用静态方法详解
核心概念:Comparator 是什么?
Comparator 是一个函数式接口(在 Java 8 中被标注为 @FunctionalInterface),它位于 java.util 包下。

它的核心作用是定义一个临时的、外部的比较规则,你可以把它想象成一个“裁判”,这个裁判知道如何比较两个任意对象的大小,然后告诉你谁大、谁小,或者相等。
Comparator 接口中最核心的方法是 compare(T o1, T o2):
int compare(T o1, T o2);
- 返回值:
- 负整数 (
o1 - o2 < 0):表示o1小于o2。 - 零 (
o1 - o2 == 0):表示o1等于o2。 - 正整数 (
o1 - o2 > 0):表示o1大于o2。
- 负整数 (
为什么需要 Comparator? (与 Comparable 的对比)
要理解 Comparator 的强大,首先要了解它的“兄弟” Comparable。
Comparable (内部比较规则)
- 定义:当一个类实现了
Comparable接口,它就拥有了内在的、默认的比较规则。 - 位置:比较逻辑写在要比较的类本身内部。
- 方法:
int compareTo(T o); - 例子:
String类、Integer类、Double类都实现了Comparable,所以它们可以直接使用Collections.sort()或Arrays.sort()进行排序。
// String 类内部定义了如何比较两个字符串 String s1 = "apple"; String s2 = "banana"; // s1.compareTo(s2) 会返回一个负数,因为 "apple" < "banana" int result = s1.compareTo(s2);
局限性:Comparable 的规则是固定的。String 类默认按字典序排序,如果你想按字符串长度排序,就必须去修改 String 类的源码,这显然是不可能的。

Comparator (外部比较规则)
- 定义:
Comparator是一个外部的、临时的比较规则。 - 位置:比较逻辑写在要比较的类之外,可以随时创建和修改。
- 优点:
- 灵活性:同一个类的对象,可以根据需要使用多种不同的排序规则(按姓名、按年龄、按薪资等)。
- 解耦:业务逻辑与排序规则分离,代码更清晰。
- 不侵入性:你不需要修改被排序的类的源码(比如一些第三方库的类,你无法修改其源码)。
| 特性 | Comparable | Comparator |
| :--- | :--- | :--- |
| 比较规则位置 | 在类内部实现 | 在类外部定义 |
| 数量 | 一个类只能有一个默认规则 | 可以有任意多个不同规则 |
| 修改方式 | 需要修改源码 | 无需修改源码,随时创建 |
| 核心方法 | compareTo(T o) | compare(T o1, T o2) |
| 适用场景 | 定义了该对象的“自然排序” (Natural Ordering) | 需要多种排序方式,或无法修改源码时 |
如何使用 Comparator?
假设我们有一个 Person 类,我们想对 Person 对象列表进行排序。
class Person {
private String name;
private int age;
private double salary;
// 构造器、getters、toString() 省略...
public Person(String name, int age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
public String getName() { return name; }
public int getAge() { return age; }
public double getSalary() { return salary; }
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + ", salary=" + salary + "}";
}
}
我们有 List<Person> people 列表,我们想对它进行排序。
传统匿名内部类
这种方式在 Java 8 之前很常见,但代码比较冗长。

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
List<Person> people = new ArrayList<>();
// ... 添加一些 Person 对象
// 1. 按年龄升序排序
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return Integer.compare(p1.getAge(), p2.getAge());
}
});
// 2. 按薪资降序排序
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
// 注意:降序,所以是 p2 - p1
return Double.compare(p2.getSalary(), p1.getSalary());
}
});
Java 8+ 的 Lambda 表达式 (推荐)
Comparator 是一个函数式接口,所以我们可以用更简洁的 Lambda 表达式来代替匿名内部类。
语法:(o1, o2) -> { return ...; },如果方法体只有一行,return 和 也可以省略。
import java.util.List; List<Person> people = new ArrayList<>(); // ... 添加一些 Person 对象 // 1. 按年龄升序排序 people.sort((p1, p2) -> Integer.compare(p1.getAge(), p2.getAge())); // 2. 按薪资降序排序 people.sort((p1, p2) -> Double.compare(p2.getSalary(), p1.getSalary())); // 3. 按姓名字典序排序 (String 已经实现了 Comparable) people.sort((p1, p2) -> p1.getName().compareTo(p2.getName()));
注意:从 Java 8 开始,List 接口本身提供了 sort(Comparator<? super E> c) 方法,所以可以直接对 List 调用 sort(),而不需要像以前那样用 Collections.sort(list)。
Java 8+ 的 Comparator 静态方法链式调用 (最现代、最推荐)
这是目前最流行、最易读、最强大的方式,它利用了 Comparator 接口在 Java 8 中新增的一系列静态方法和默认方法,可以像流式 API 一样链式调用。
import java.util.List;
import java.util.Comparator;
List<Person> people = new ArrayList<>();
// ... 添加一些 Person 对象
// 1. 按年龄升序 (推荐使用 Comparator.comparing)
people.sort(Comparator.comparing(Person::getAge));
// 2. 按薪资降序 (使用 thenComparing 或 reversed())
people.sort(Comparator.comparing(Person::getSalary).reversed());
// 3. 先按年龄升序,如果年龄相同,再按薪资降序 (链式调用)
people.sort(
Comparator.comparing(Person::getAge)
.thenComparing(Person::getSalary, Comparator.reverseOrder())
);
// 4. 先按姓氏排序,再按名字排序 (多级比较)
// 假设 Person 有 getLastName() 和 getFirstName() 方法
people.sort(
Comparator.comparing(Person::getLastName)
.thenComparing(Person::getFirstName)
);
Comparator.comparing(Function<? super T, ? extends U> keyExtractor):核心方法,用于提取排序键。Comparator.reverseOrder()/Comparator.naturalOrder():直接生成一个反转或自然的比较器。thenComparing(...):用于定义多级排序。reversed():将当前比较器反转。
实战案例:对复杂对象列表进行排序
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Person> people = new ArrayList<>();
people.add(new Person("Charlie", 30, 75000.0));
people.add(new Person("Alice", 25, 85000.0));
people.add(new Person("Bob", 30, 65000.0));
people.add(new Person("David", 22, 55000.0));
System.out.println("原始列表: " + people);
// 1. 按年龄升序
people.sort(Comparator.comparing(Person::getAge));
System.out.println("\n按年龄升序: " + people);
// 2. 按薪资降序
people.sort(Comparator.comparing(Person::getSalary).reversed());
System.out.println("\n按薪资降序: " + people);
// 3. 先按年龄升序,再按薪资降序 (年龄相同时,薪资高的排前面)
people.sort(
Comparator.comparing(Person::getAge)
.thenComparing(Person::getSalary, Comparator.reverseOrder())
);
System.out.println("\n按年龄升序,再按薪资降序: " + people);
// 4. 按姓名长度排序
people.sort(Comparator.comparing(p -> p.getName().length()));
System.out.println("\n按姓名长度升序: " + people);
}
}
Comparator 常用静态方法详解
| 方法 | 描述 | 示例 |
|---|---|---|
comparing(...) |
核心方法,基于某个属性(函数)创建比较器。 | Comparator.comparing(Person::getAge) |
comparingInt(...) |
专门为 int 类型的属性优化,避免自动装箱。 |
Comparator.comparingInt(Person::getAge) |
comparingLong(...) |
专门为 long 类型的属性优化。 |
Comparator.comparingLong(Person::getId) |
comparingDouble(...) |
专门为 double 类型的属性优化。 |
Comparator.comparingDouble(Person::getSalary) |
naturalOrder() |
生成一个按照元素“自然排序”的比较器(要求元素实现了 Comparable)。 |
Comparator.naturalOrder() |
reverseOrder() |
生成一个与“自然排序”相反的比较器。 | Comparator.reverseOrder() |
nullsFirst(...) |
将 null 值视为“最小”值,放在列表最前面,需要一个 Comparator 来比较非 null 元素。 |
Comparator.nullsFirst(Comparator.comparing(Person::getName)) |
nullsLast(...) |
将 null 值视为“最大”值,放在列表最后面,需要一个 Comparator 来比较非 null 元素。 |
Comparator.nullsLast(Comparator.comparing(Person::getName)) |
thenComparing(...) |
多级排序,当前比较器结果相同时,使用下一个比较器。 | c1.thenComparing(c2) |
reversed() |
反转当前比较器的排序结果。 | c.reversed() |
Comparator是 Java 排序的瑞士军刀,提供了无与伦比的灵活性。- 当你需要多种排序方式,或者无法修改被排序类的源码时,
Comparator是你的不二之选。 - 推荐使用 Java 8+ 的新特性:优先使用
Comparator.comparing()和 Lambda 表达式,代码更简洁、更易读、更不易出错。 - 掌握
Comparator的链式调用(comparing(),thenComparing(),reversed())是编写复杂排序逻辑的关键。
希望这份详细的指南能帮助你彻底理解并掌握 Java 中的 Comparator!
