Java 集合排序提供兩條正交路徑:實體自帶比較邏輯 (Comparable) 與 外部注入比較策略 (Comparator)。本文以 Student (姓名、年齡) 為例,完整展示兩種方案代碼、List.sort()/Collections.sort() 調用差異、多欄位排序組合、Lambda 簡寫與效能考量。
public class Student implements Comparable<Student> {
private String name;
private int age;
// 建構子、getter/setter 省略
@Override
public int compareTo(Student o) {
// 1. 姓名升序
int cmp = this.name.compareTo(o.name);
// 2. 姓名相同,年齡升序
if (cmp == 0) cmp = Integer.compare(this.age, o.age);
return cmp;
}
}
// 使用
List<Student> list = new ArrayList<>();
list.add(new Student("b", 12));
list.add(new Student("a", 10));
list.add(new Student("b", 11));
list.add(new Student("ac", 20));
list.sort(null); // 或 Collections.sort(list)
// 結果: a/10, ac/20, b/11, b/12
public class Student {
private String name;
private int age;
// getter/setter
}
// 單一職責 Comparator
public class StudentNameAgeComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
int cmp = o1.getName().compareTo(o2.getName());
if (cmp == 0) cmp = Integer.compare(o1.getAge(), o2.getAge());
return cmp;
}
}
// 使用
list.sort(new StudentNameAgeComparator());
// 或 Lambda (Java 8+)
list.sort(Comparator.comparing(Student::getName)
.thenComparingInt(Student::getAge));
// 反序
list.sort(Comparator.comparing(Student::getName).reversed()
.thenComparingInt(Student::getAge));
| 維度 | Comparable | Comparator |
|---|---|---|
| 定義位置 | 實體類內部 | 獨立類/靜態內部類/Lambda |
| 修改排序規則 | 修改實體代碼 (侵入式) | 新增/替換 Comparator (非侵入) |
| 多種排序共存 | 只能有一種自然順序 | 可定義無限種 (按姓名/年齡/註冊時間...) |
| 適用場景 | 單一、固定、領域核心排序 | 多變、場景相關、第三方類無法修改 |
| 調用方式 | list.sort(null) | list.sort(comparator) |
// 空值安全:null 排最後
Comparator<Student> nullSafe = Comparator
.comparing(Student::getName, Comparator.nullsLast(Comparator.naturalOrder()))
.thenComparingInt(Student::getAge);
// 多欄位混合升降序
list.sort(Comparator
.comparing(Student::getName) // 姓名升序
.thenComparing(Student::getAge, Comparator.reverseOrder()) // 年齡降序
.thenComparing(Student::getId)); // ID 升序兜底
// 原始類型專用比較器 (避免裝箱)
.thenComparingInt(Student::getAge)
.thenComparingLong(Student::getScore)
.thenComparingDouble(Student::getRate)
List.sort 使用 TimSort (歸併+插入混合),近乎有序數據 O(n),隨機 O(n log n),穩定排序。static final 常量或單例,避免重複創建。thenComparingInt/Long/Double:避免自動裝箱開銷。Arrays.parallelSort(arr, comparator) (需數組,List 先 toArray)。compareTo/compare 純函數無副作用。Comparable 定義「自然順序」,Comparator 定義「場景順序」。新代碼**優先用 Comparator + Lambda 鏈式組合** (非侵入、可讀、可組合、可測試);只有領域模型確有「唯一自然順序」語義時 (如 ID、時間戳) 才實作 Comparable。掌握 Comparator.comparing/thenComparing/nullsFirst/reverseOrder 全家桶,即能優雅解決 99% 排序需求。