場景一:自定義對象多條件排序
class Student { String name; int age; /* getter/setter */ }
List list = Arrays.asList(
new Student("丁曉宇", 21), new Student("趙四", 22),
new Student("張三", 11), new Student("劉武", 19)
);
// 姓名升序,同年齡升序
list.sort(Comparator.comparing(Student::getName)
.thenComparingInt(Student::getAge));
// 年齡降序,同名升序
list.sort(Comparator.comparingInt(Student::getAge).reversed()
.thenComparing(Student::getName));
場景二:基本類型 / String 直接排序
List nums = Arrays.asList(5, 2, 8, 1);
nums.sort(Integer::compareTo); // 升序
nums.sort(Comparator.reverseOrder()); // 降序
List words = Arrays.asList("banana", "apple", "pear");
words.sort(String::compareToIgnoreCase); // 忽略大小寫
場景三:傳統 Comparator 實作類(可復用/序列化)
class AgeComparator implements Comparator, Serializable {
@Override public int compare(Student s1, Student s2) {
return Integer.compare(s1.getAge(), s2.getAge());
}
}
// 使用
list.sort(new AgeComparator());
核心 API 對比表
| 方法 | 適用 | 優點 |
Collections.sort(list, cmp) | List 介面 | JDK 7 通用 |
list.sort(cmp) | ArrayList 等 | 預設方法、更 OO |
comparing(Function) | 提取鍵值 | 自動處理 null、可鏈式 |
thenComparingInt/Long/Double | 基本型別次鍵 | 避免裝箱、效能高 |
nullsFirst/Last() | 空值策略 | 不拋 NPE |
避坑指南
- 減法溢位:
s1.age - s2.age → 用 Integer.compare 或 thenComparingInt
- 違反傳遞性:比較器必須滿足
sgn(c(a,b)) = -sgn(c(b,a)) 且傳遞性
- 修改排序中對象:不可在比較器中修改被比較對象狀態
- 穩定性:
Collections.sort 為穩定排序(TimSort),相等元素相對位置不變
進階:並行排序大數據
// Java 8+ 數組並行排序
Arrays.parallelSort(arr); // 多核加速
// List 轉數組並行排序後再轉回(或用並行流)
list.parallelStream().sorted(cmp).collect(toList());