Java Comparable 與 Comparator
Comparable 和 Comparator 是 Java 中用於比較和排序物件的兩個介面。
Comparable
物件實作 Comparable 介面來定義自然排序:
public class Person implements Comparable<Person> {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int compareTo(Person other) {
return this.age - other.age; // 依年齡排序
}
}
// 使用
List<Person> people = new ArrayList<>();
people.add(new Person("Alice", 25));
people.add(new Person("Bob", 20));
people.add(new Person("Charlie", 30));
Collections.sort(people); // 使用 compareTo 排序
// 結果:Bob(20), Alice(25), Charlie(30)
compareTo 回傳值
| 回傳值 | 意義 |
|---|---|
| 負數 | this < other |
| 0 | this == other |
| 正數 | this > other |
Comparator
Comparator 是獨立的比較器,用於提供外部排序邏輯:
// 依名字排序的 Comparator
Comparator<Person> byName = new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.getName().compareTo(p2.getName());
}
};
// Lambda 寫法
Comparator<Person> byName = (p1, p2) -> p1.getName().compareTo(p2.getName());
// 方法參考
Comparator<Person> byName = Comparator.comparing(Person::getName);
// 使用
Collections.sort(people, byName);
Comparator 工廠方法
// comparing - 依屬性排序
Comparator<Person> byAge = Comparator.comparing(Person::getAge);
Comparator<Person> byName = Comparator.comparing(Person::getName);
// 反向排序
Comparator<Person> byAgeDesc = Comparator.comparing(Person::getAge).reversed();
// 多欄位排序
Comparator<Person> byAgeAndName = Comparator
.comparing(Person::getAge)
.thenComparing(Person::getName);
// null 處理
Comparator<Person> nullsFirst = Comparator.nullsFirst(byAge);
Comparator<Person> nullsLast = Comparator.nullsLast(byAge);
// 自然排序
Comparator<String> natural = Comparator.naturalOrder();
Comparator<String> reverse = Comparator.reverseOrder();
數值比較
// 避免溢位問題
Comparator<Person> byAge = Comparator.comparingInt(Person::getAge);
Comparator<Account> byBalance = Comparator.comparingLong(Account::getBalance);
Comparator<Product> byPrice = Comparator.comparingDouble(Product::getPrice);
在各種場景使用
Collections.sort()
List<Person> people = new ArrayList<>();
Collections.sort(people); // 使用 Comparable
Collections.sort(people, byName); // 使用 Comparator
List.sort()
people.sort(byAge);
people.sort(Comparator.comparing(Person::getName).reversed());
Stream.sorted()
people.stream()
.sorted(Comparator.comparing(Person::getAge))
.collect(Collectors.toList());
TreeSet / TreeMap
// 使用 Comparable
TreeSet<Person> set1 = new TreeSet<>();
// 使用 Comparator
TreeSet<Person> set2 = new TreeSet<>(byName);
TreeMap<Person, String> map = new TreeMap<>(byAge);
PriorityQueue
// 最小堆(預設)
PriorityQueue<Person> minHeap = new PriorityQueue<>(byAge);
// 最大堆
PriorityQueue<Person> maxHeap = new PriorityQueue<>(byAge.reversed());
Comparable vs Comparator
| 特性 | Comparable | Comparator |
|---|---|---|
| 位置 | 類別內部 | 類別外部 |
| 方法 | compareTo | compare |
| 排序方式 | 自然排序(唯一) | 可定義多種 |
| 修改類別 | 需要 | 不需要 |
實用範例
多條件排序
List<Person> people = Arrays.asList(
new Person("Alice", 25),
new Person("Bob", 25),
new Person("Alice", 30)
);
// 先依年齡,再依名字
people.sort(Comparator
.comparing(Person::getAge)
.thenComparing(Person::getName));
// Alice(25), Bob(25), Alice(30)
處理 null
List<String> items = Arrays.asList("B", null, "A", null, "C");
items.sort(Comparator.nullsLast(Comparator.naturalOrder()));
// [A, B, C, null, null]
items.sort(Comparator.nullsFirst(Comparator.naturalOrder()));
// [null, null, A, B, C]
自訂排序規則
// 字串依長度排序,長度相同依字母排序
Comparator<String> byLengthThenAlpha = Comparator
.comparingInt(String::length)
.thenComparing(Comparator.naturalOrder());
List<String> words = Arrays.asList("cat", "elephant", "dog", "ant");
words.sort(byLengthThenAlpha);
// [ant, cat, dog, elephant]
重點整理
Comparable定義物件的自然排序,實作compareTo()Comparator提供外部排序邏輯,實作compare()- 使用
Comparator.comparing()簡潔地建立比較器 thenComparing()串接多個排序條件reversed()反轉排序順序nullsFirst()/nullsLast()處理 null 值