Comparable接口用于定义类的唯一自然排序,需在类内部实现compareTo方法;Comparator是外部灵活排序工具,支持链式调用与null安全处理,适用于不可修改类或多种排序策略。
Comparable 接口必须在类内部实现
如果一个类天然具有“自然顺序”,比如 String 按字典序、Integer 按数值大小,就该让这个类实现 Comparable 接口。它只有一个方法:compareTo(T o),返回负数、0 或正数,分别表示“小于”“等于”“大于”当前对象。
关键限制:一个类只能有一个 compareTo 实现,也就是说,Comparable 只能定义一种默认排序逻辑。你不能靠它支持姓名升序、年龄降序、部门分组等多种策略。
常见错误是把 compareTo 写成布尔返回值,或在比较前没处理 null —— compareTo 方法里如果传入 null,多数 JDK 实现会直接抛 NullPointerException,不是静默跳过。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 优先用
Objects.compare(a, b, Comparator.naturalOrder())代替手写 null 判断和类型转换 - 多个字段组合比较时,用
Comparator.comparing(...).thenComparing(...)链式调用更安全(见下节) - 若类已发布且无法修改源码(如第三方库的
User类),就别硬塞Comparable,改用Comparator
Comparator 是外部定义的灵活排序工具
Comparator 是函数式接口,核心方法是 compare(T o1, T o2)。它不侵入业务类,所有排序逻辑都写在外面,随时可换。
Java 8 起,Comparator 提供大量静态工厂方法,大幅降低手写逻辑成本:
-
Comparator.comparing(User::getName)→ 按姓名升序 -
Comparator.comparing(User::getAge).reversed()→ 按年龄降序 -
Comparator.comparing(User::getDept).thenComparing(User::getSalary)→ 先按部门,部门相同时再按薪资
注意:这些方法返回的是不可变的 Comparator 实例,线程安全;但如果你用 lambda 捕获了可变变量(比如一个动态配置的排序字段名),那就得自己保证线程安全。