| 維度 | Comparable<T> | Comparator<T> |
|---|---|---|
| 定義位置 | 類內部(實作介面) | 類外部(獨立類或 Lambda) |
| 核心方法 | int compareTo(T o) | int compare(T o1, T o2) |
| 語義 | 「自然順序」 | 「定製順序」/ 多種排序策略 |
| 適用場景 | 單一預設排序、TreeSet/TreeMap 鍵 | 多維度排序、第三方類無法修改 |
| 排序呼叫 | Collections.sort(list) | Collections.sort(list, cmp) |
public class Person implements Comparable{ private String name; private int age; // 自然順序:按姓名字典序 @Override public int compareTo(Person o) { return this.name.compareTo(o.name); // null 安全需自行處理 } } // 使用 List list = Arrays.asList(new Person("Bob", 30), new Person("Alice", 25)); Collections.sort(list); // 按 name 排序
class AgeAscComparator implements Comparator{ @Override public int compare(Person a, Person b) { return Integer.compare(a.getAge(), b.getAge()); } } class AgeDescComparator implements Comparator { @Override public int compare(Person a, Person b) { return Integer.compare(b.getAge(), a.getAge()); } } // 使用 Collections.sort(list, new AgeAscComparator()); Collections.sort(list, new AgeDescComparator());
// 年齡升序
list.sort(Comparator.comparingInt(Person::getAge));
// 年齡降序
list.sort(Comparator.comparingInt(Person::getAge).reversed());
// 先按姓名,姓名相同再按年齡
list.sort(Comparator.comparing(Person::getName)
.thenComparingInt(Person::getAge));
import static java.util.Comparator.*;
list.sort(comparing(Person::getName)
.thenComparing(comparingInt(Person::getAge).reversed()));
// null 排在最後 ComparatornullsLast = Comparator.nullsLast(comparing(Person::getName)); // 組合:先按部門,部門相同按薪資降序,薪資相同按姓名 list.sort(comparing(Person::getDept) .thenComparing(comparingDouble(Person::getSalary).reversed()) .thenComparing(Person::getName));
// 自然順序(Person 必須實作 Comparable) SettreeSet = new TreeSet<>(); // 定製順序(無需 Person 實作 Comparable) Set treeSet2 = new TreeSet<>(Comparator.comparingInt(Person::getAge)); Map treeMap = new TreeMap<>(Comparator.comparing(Person::getName));
compareTo/compare 返回 int,禁止用減法(a - b 可能溢位),改用 Integer.compare(a, b) 或 Long.compare。Comparable 類最好實作 equals 並保持一致:compareTo(x) == 0 ⇔ equals(x)。list.sort(cmp)(原地排序),避免 stream().sorted() 額外開銷。comparingInt/Long/Double 避免自動裝箱。Comparable = 內建自然序(單一、侵入式);
Comparator = 外部策略(多重、非侵入、函數式組合)。
Java 8+ 推薦 Comparator 靜態工廠 + Lambda 鏈式調用,代碼更聲明式、可讀性更強。