Java 比较器如何入门
Java 比较器(Comparator)是处理对象排序的核心工具,尤其当对象没有自然顺序(如自定义类)或需要多种排序规则时。以下是入门指南,从核心概念到实战示例逐步讲解:
一、核心概念:Comparable vs Comparator
Java 中有两种排序接口,先明确区别:
- Comparable(自然排序):对象自身实现的接口(如
String、Integer默认实现),定义默认排序规则,需修改对象类代码。 - Comparator(定制排序):外部定义的比较器,不修改对象类,可灵活定义多种排序规则,是入门重点。
二、Comparator 基础:如何实现?
Comparator 是函数式接口(仅一个抽象方法 compare(T o1, T o2)),返回值规则:
- o1 < o2:返回负数(如
-1) - o1 == o2:返回0
- o1 > o2:返回正数(如
1)
实现方式(3种):
- 传统匿名内部类(Java 7及之前的主流方式)
- Lambda 表达式(Java 8+,简化写法)
- 方法引用(Java 8+,更简洁,需配合函数式接口)
三、实战示例:自定义对象排序
假设我们有一个 Student 类,需按年龄升序、姓名降序等规则排序,且不想修改 Student 类本身。
步骤1:定义 Student 类(无 Comparable 实现)
class Student {
private String name;
private int age;
private double score;
// 构造器、getter/setter、toString 省略
public Student(String name, int age, double score) {
this.name = name;
this.age = age;
this.score = score;
}
// getter 方法
public String getName() { return name; }
public int getAge() { return age; }
public double getScore() { return score; }
}
步骤2:使用 Comparator 排序
示例1:按年龄升序排序(Lambda 表达式)
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class ComparatorDemo {
public static void main(String[] args) {
List students = new ArrayList<>();
students.add(new Student("Alice", 20, 85.5));
students.add(new Student("Bob", 18, 90.0));
students.add(new Student("Charlie", 20, 88.0));
// 方法1:Lambda 表达式(最常用)
Comparator ageAscComparator = (s1, s2) -> s1.getAge() - s2.getAge();
// 等价于:Comparator.comparingInt(Student::getAge)
Collections.sort(students, ageAscComparator);
// 输出结果:Bob(18) → Alice(20) → Charlie(20)
students.forEach(s -> System.out.println(s.getName() + ":" + s.getAge()));
}
}
示例2:按姓名降序排序(方法引用)
// 方法引用:Student::getName 提取姓名,再按字符串降序(默认升序,reverse 反转)
Comparator nameDescComparator = Comparator.comparing(Student::getName).reversed();
Collections.sort(students, nameDescComparator);
// 输出:Charlie → Bob → Alice(按姓名首字母降序)
示例3:多条件排序(先年龄升序,年龄相同再分数降序)
// 链式调用:先按年龄升序,再按分数降序
Comparator multiComparator = Comparator
.comparingInt(Student::getAge) // 年龄升序
.thenComparing(Comparator.comparingDouble(Student::getScore).reversed()); // 分数降序
Collections.sort(students, multiComparator);
示例4:传统匿名内部类(Java 7 写法,了解即可)
// 不使用 Lambda,用匿名内部类实现 Comparator
Comparator ageComparator = new Comparator() {
@Override
public int compare(Student s1, Student s2) {
return Integer.compare(s1.getAge(), s2.getAge()); // 推荐用 Integer.compare 避免溢出
}
};
四、常用工具方法(Java 8+)
Comparator 提供了大量静态方法简化排序逻辑:
| 方法 | 作用 | 示例 |
|---|---|---|
comparing(Function) |
按对象的某个属性升序 | Comparator.comparing(Student::getAge) |
comparingInt/Long/Double |
按基本类型属性升序(避免装箱) | Comparator.comparingInt(Student::getAge) |
reversed() |
反转当前排序规则 | comparator.reversed() |
thenComparing(Comparator) |
多条件排序(次要规则) | comparator.thenComparing(...) |
五、常见误区
- 返回值不要直接写
o1 - o2:若o1和o2是int且可能溢出(如o1=2^31-1, o2=-1),结果会错误。推荐用Integer.compare(o1, o2)。 - 区分
Comparable和Comparator:前者是对象自身的“默认排序”,后者是外部“定制排序”。 Collections.sortvsList.sort:Java 8 后List有默认方法sort(Comparator),可直接调用:students.sort(ageAscComparator)。
六、总结入门步骤
- 明确排序需求(按什么字段、升序/降序、多条件?)。
- 用
Comparator接口实现比较逻辑(优先 Lambda 或Comparator静态方法,简洁)。 - 调用
Collections.sort(list, comparator)或list.sort(comparator)排序。
通过以上示例,你可以快速掌握 Comparator 的基本用法,后续可尝试更复杂的场景(如排序 Map 的键值对、自定义复杂对象的多维度排序)。