目录
- 背景和价值
- 一、
Comparator
的基本用法 - 二、 Java 8 之前(匿名内部类)
- 三、 Java 8 之后(Lambda 表达式和方法引用)
- 1. 使用 Lambda 表达式
- 2. 使用静态工厂方法
Comparator.comparing()
(推荐) - 3. 链式比较(多条件排序)
- 4. 处理
null
值
- 总结要点
- 一、
- 参考资料
背景和价值
Java 中的比较器(Comparator)是函数式编程中非常重要的一部分,它主要用于自定义排序规则。在 Java 8 之后,结合 Lambda 表达式和 Stream API,它的用法变得更加简洁和强大。
Java 提供了两种主要的比较机制:
Comparable
接口: 用于对象自身的默认排序(自然排序)。Comparator
接口: 用于定义外部的自定义排序规则。
一、 Comparator
的基本用法
Comparator<T>
是一个函数式接口,只有一个抽象方法:
public interface Comparator<T> {int compare(T o1, T o2); // 核心方法// ... default 和 static 方法
}
- 如果
compare(o1, o2)
返回 负数,表示o1
排在o2
前面。 - 如果
compare(o1, o2)
返回 零,表示o1
和o2
相等。 - 如果
compare(o1, o2)
返回 正数,表示o1
排在o2
后面。
二、 Java 8 之前(匿名内部类)
在 Java 8 之前,你需要使用匿名内部类来实现 Comparator
:
List<Student> students = new ArrayList<>();
// ... 填充数据// 按分数升序排序
Collections.sort(students, new Comparator<Student>() {@Overridepublic int compare(Student s1, Student s2) {return s1.getScore() - s2.getScore();// 或使用包装类的方法:Integer.compare(s1.getScore(), s2.getScore());}
});
三、 Java 8 之后(Lambda 表达式和方法引用)
Java 8 极大地简化了 Comparator
的使用。
1. 使用 Lambda 表达式
由于 Comparator
是一个函数式接口,可以直接用 Lambda 表达式实现 compare
方法:
// 按分数升序排序
Collections.sort(students, (s1, s2) -> s1.getScore() - s2.getScore());// 在 Stream 中使用 (分数降序排序)
students.stream().sorted((s1, s2) -> s2.getScore() - s1.getScore()) // s2 减 s1 实现降序.forEach(System.out::println);
2. 使用静态工厂方法 Comparator.comparing()
(推荐)
这是最推荐的方式,它允许你使用方法引用来指定排序的键(key):
- 按分数升序:
students.stream().sorted(Comparator.comparing(Student::getScore)) // 默认升序.forEach(System.out::println);
- 按分数降序:
students.stream().sorted(Comparator.comparing(Student::getScore).reversed()) // .reversed() 翻转顺序.forEach(System.out::println);
- 按字符串(例如:姓名)升序:
students.stream().sorted(Comparator.comparing(Student::getName)).forEach(System.out::println);
3. 链式比较(多条件排序)
你可以使用 thenComparing()
来指定第二个、第三个等排序规则,这在第一个字段相同时非常有用。
示例:先按专业升序,如果专业相同,则按分数降序。
students.stream().sorted(Comparator.comparing(Student::getMajor) // 1. 主要排序:按专业升序.thenComparing(Comparator.comparing(Student::getScore).reversed()) // 2. 次要排序:按分数降序).forEach(System.out::println);
4. 处理 null
值
如果排序字段可能为 null
,可以使用 nullsFirst()
或 nullsLast()
来指定 null
值的排序位置。
示例:按姓名排序,null
姓名排在最后。
students.stream().sorted(Comparator.comparing(Student::getName, Comparator.nullsLast(String::compareTo))).forEach(System.out::println);
总结要点
用法 | 描述 | 示例 |
---|---|---|
基础升序 | 使用 comparing() 传入 Getter 方法引用。 |
Comparator.comparing(Student::getScore) |
基础降序 | 在基础升序后调用 reversed() 。 |
Comparator.comparing(Student::getScore).reversed() |
多条件排序 | 使用 thenComparing() 链接多个比较器。 |
comparing(...).thenComparing(...) |
原始类型 | comparingInt() , comparingLong() , comparingDouble() 效率更高。 |
Comparator.comparingInt(Student::getScore) |
处理 Null | 使用 nullsFirst() 或 nullsLast() 包裹。 |
Comparator.nullsFirst(Comparator.comparing(Student::getName)) |