核心區別一句話
- Comparable:**內部**比較,「我自己怎麼排」,類實現
compareTo(T o),**一種**自然順序。
- Comparator:**外部**比較,「我幫你排」,獨立類實現
compare(T o1, T o2),**多種**定製順序。
Comparable 自然排序實戰
public class Student implements Comparable {
private int id;
private String name;
private double gpa;
// getter/setter/構造器省略
@Override
public int compareTo(Student other) {
// 按 id 升序
return Integer.compare(this.id, other.id);
}
@Override public String toString() { return "Student(id=" + id + ", name=" + name + ")"; }
}
// 使用
List list = Arrays.asList(new Student(3,"C"), new Student(1,"A"), new Student(2,"B"));
Collections.sort(list); // 或 list.sort(null)
System.out.println(list); // [Student(id=1...), Student(id=2...), Student(id=3...)]
Comparator 定製排序實戰
1. 匿名內部類 / Lambda(Java 8+ 推薦)
// 按 GPA 降序
list.sort((s1, s2) -> Double.compare(s2.getGpa(), s1.getGpa()));
// 多字段:先 GPA 降序,再 id 升序
list.sort(Comparator
.comparing(Student::getGpa).reversed()
.thenComparing(Student::getId));
// 空值安全:null 排最後
list.sort(Comparator.nullsLast(Comparator.comparing(Student::getName)));
2. 獨立 Comparator 類(復用、序列化、Spring Bean 注入)
public class StudentNameComparator implements Comparator, Serializable {
@Override
public int compare(Student s1, Student s2) {
return s1.getName().compareTo(s2.getName());
}
}
// 使用
list.sort(new StudentNameComparator());
TreeSet / TreeMap 依賴比較器
| 構造方式 | 比較來源 | 適用場景 |
new TreeSet() | 元素必須實現 Comparable | 單一自然順序、元素類可控 |
new TreeSet(comparator) | 外部 Comparator | 多種順序、元素類不可修改(如第三方類) |
// 同一數據,兩種視圖
Set byId = new TreeSet<>(list); // 自然順序
Set byGpa = new TreeSet<>(Comparator.comparing(Student::getGpa).reversed());
byGpa.addAll(list); // 自動按 GPA 降序去重
Stream 排序
List top3 = list.stream()
.sorted(Comparator.comparing(Student::getGpa).reversed())
.limit(3)
.toList();
避坑指南
- compareTo 與 equals 不一致:
compareTo(e1, e2) == 0 應隱含 e1.equals(e2),否則 TreeSet 會出現「邏輯相等但集合視為不同」的 Bug。
- 溢出風險:
return this.id - other.id 若 id 差值超過 Integer.MAX_VALUE 會溢出,**必須用 Integer.compare 或 Long.compare**。
- 空指針:Comparator 鏈中加入
Comparator.nullsFirst/Last,或確保字段非空。
- 序列化:作為 TreeSet 比較器的 Comparator 必須實現
Serializable,否則集合序列化失敗。
總結選型表
| 場景 | 推薦 |
| 實體類有明顯「自然順序」(如 ID、時間戳) | 實現 Comparable |
| 需要多種排序(按姓名、按成績、按註冊時間) | 編寫多個 Comparator |
| 第三方類無法修改 | 外部 Comparator |
| TreeSet/TreeMap 去重並排序 | 構造時傳入 Comparator |
| Stream/Collections.sort 一次性排序 | Lambda 內聯 Comparator |
掌握 Comparable 定自然序、Comparator 定定製序、Comparator.comparing/thenComparing/nullsFirst 鏈式組合,即可輕鬆駕馭 Java 所有排序場景。