陣列或集合裡的物件 (如 Course) 沒有天生的大小關係。Arrays.sort() 需要一個「比較契約」:任意兩個物件 a、b,能判斷 a<b、a=b、a>b。Java 用介面定義這個契約:
Comparable<T>:物件自己知道怎麼跟別人比 (自然排序)。Comparator<T>:外部裁判決定怎麼比 (客製排序)。public class Course {
private String title;
private double price;
// 建構子、getter/setter 略
}
public class Course implements Comparable<Course> {
// ... 原有欄位 ...
@Override
public int compareTo(Course other) {
if (other == null) return 1;
return Double.compare(this.price, other.price); // 價格升序
}
}
// 使用
Course[] courses = { new Course("Java", 2000), new Course("Python", 1500) };
Arrays.sort(courses); // 直接排序,不傳比較器
// 結果:Python(1500), Java(2000)
⚠️ 限制:一個類別只能有一種自然排序。若明天要按標題字母序排,compareTo 無法同時滿足。
import java.util.Comparator;
public class PriceComparator implements Comparator<Course> {
@Override
public int compare(Course c1, Course c2) {
if (c1 == c2) return 0;
if (c1 == null) return -1;
if (c2 == null) return 1;
return Double.compare(c1.getPrice(), c2.getPrice());
}
}
// 使用
Arrays.sort(courses, new PriceComparator()); // 傳入比較器
// 同一組資料,換個比較器即可按標題排
Arrays.sort(courses, Comparator.comparing(Course::getTitle));
List list = Arrays.asList(courses);
// 價格降序
list.sort(Comparator.comparingDouble(Course::getPrice).reversed());
// 價格升序 -> 標題降序
list.sort(Comparator
.comparingDouble(Course::getPrice)
.thenComparing(Comparator.comparing(Course::getTitle).reversed()));
// null 安全:沒價格的排最後
list.sort(Comparator.nullsLast(Comparator.comparingDouble(Course::getPrice)));
| 錯誤寫法 | 問題 | 修正 |
|---|---|---|
return this.price - other.price; | double 相減可能溢位/精度遺失 | Double.compare(this.price, other.price) |
return (int)(this.price - other.price); | 強制轉型截斷,大數字會判斷錯誤 | 同上 |
忘記處理 null | 拋 NullPointerException | 先判斷 if (o == null) return 1; 或用 nullsLast |
compareTo 與 equals 不一致 | TreeSet 會把不相等物件視為重複 | 主鍵相等時 compareTo 必須回 0 |
Student(name, score) 類別,實作 Comparable 依分數降序。NameComparator 依姓名筆畫數排序 (提示:Collator.getInstance(Locale.TRADITIONAL_CHINESE))。NameComparator 排序並印出。Comparable = 內建預設排序,implements Comparable<T> + compareTo。Comparator = 外部可換裝排序,implements Comparator<T> + compare,或用 Lambda。Double.compare/Integer.compare 避免溢位。Comparator.comparing/thenComparing/reversed/nullsLast 鏈式 API,程式碼最乾淨。