编写Comparator核心是实现compare方法返回负数、0或正数,逻辑需清晰、防空指针、语义一致;推荐自然顺序类实现Comparable接口;注意无副作用、防溢出、满足比较器三大性质。

编写 Comparator 的核心是实现 compare(T o1, T o2) 方法,返回负数、0 或正数,分别表示 o1 小于、等于、大于 o2。关键在于逻辑清晰、避免空指针、符合排序语义(如升序/降序),且保持一致性(compare(a,b) > 0 应与 compare(b,a) 对应)。
基础写法:匿名内部类或 Lambda 表达式
对简单类型(如 String、Integer)或对象的某个字段排序,推荐用 Lambda,简洁安全:
- 按字符串长度升序:
Comparator.comparing(String::length) - 按整数属性降序:
Comparator.comparing(Person::getAge).reversed() - 多字段组合(先按姓名升序,姓名相同时按年龄降序):
Comparator.comparing(Person::getName).thenComparing(Person::getAge, Comparator.reverseOrder())
自定义比较逻辑:处理 null 和复杂规则
当字段可能为 null,或需特殊判断(如忽略大小写、按状态优先级排序),建议用 Comparator.nullsFirst() / nullsLast() 包装,或手动处理:
- 姓名可为空,空值排最后:
Comparator.nullsLast(String.CASE_INSENSITIVE_ORDER).onResultOf(Person::getName) - 按自定义状态顺序("PENDING" < "PROCESSING" < "DONE"):
Comparator.comparing(p -> {<br> return switch (p.getStatus()) {<br> case "PENDING" -> 1;<br> case "PROCESSING" -> 2;<br> case "DONE" -> 3;<br> default -> 4;<br> };<br> })
实现 Comparable 接口(替代方案)
如果该类有明确的“自然顺序”,更推荐让类自身实现 Comparable 接口(即重写 compareTo),这样 Collections.sort(list) 或 TreeSet 可直接使用,无需每次都传 Comparator。例如:
public class Person implements Comparable<Person> {<br>
private String name;<br>
private int age;<br><br>
@Override<br>
public int compareTo(Person other) {<br>
if (other == null) return 1;<br>
int nameCmp = Objects.compare(this.name, other.name, String.CASE_INSENSITIVE_ORDER);<br>
if (nameCmp != 0) return nameCmp;<br>
return Integer.compare(this.age, other.age);<br>
}<br>
}
注意事项和常见坑
-
不要在
compare中修改对象状态 —— 比较器必须是无副作用的纯函数 -
避免用减法计算整数差(如
a - b),可能整型溢出;改用Integer.compare(a, b) -
确保对称性、传递性、自反性:若
compare(a,b)==0,则a.equals(b)最好也为 true(非强制但强烈建议) - 排序集合(如
TreeSet)时,若Comparator与equals不一致,可能导致contains返回 false(即使元素存在)


















