Comparator 在 Java 8 成為函數式接口(單一抽象方法 compare(T o1, T o2)),配合 Lambda 與方法引用,排序代碼從「匿名內部類地獄」蛻變為流暢的鏈式表達。本文演示從基礎排序到多級組合、極值查找的完整實戰。
class Person {
private final String name;
private final int age;
public Person(String name, int age) { this.name = name; this.age = age; }
public String getName() { return name; }
public int getAge() { return age; }
public int ageDifference(Person other) { return age - other.age; }
@Override public String toString() { return String.format("%s - %d", name, age); }
}
List<Person> ascendingAge = people.stream()
.sorted((p1, p2) -> p1.ageDifference(p2)) // Lambda
.collect(toList());
List<Person> ascendingAge = people.stream()
.sorted(Person::ageDifference) // 極簡
.collect(toList());
輸出:
John - 20
Sara - 21
Jane - 21
Greg - 35
Comparator<Person> byAgeAsc = Comparator.comparingInt(Person::getAge);
Comparator<Person> byAgeDesc = byAgeAsc.reversed(); // 零成本反轉
people.stream().sorted(byAgeAsc).collect(toList());
people.stream().sorted(byAgeDesc).collect(toList());
reversed() 是默認方法,內部交換參數順序,屬於高階函數(返回新 Comparator)。
Function<Person, String> byName = Person::getName;
people.stream()
.sorted(comparing(byName)) // 靜態導入 comparing
.collect(toList());
輸出(字典序):
Greg - 35
Jane - 21
John - 20
Sara - 21
Function<Person, Integer> byAge = Person::getAge;
Function<Person, String> byName = Person::getName;
List<Person> result = people.stream()
.sorted(comparing(byAge).thenComparing(byName)) // 先年齡後名字
.collect(toList());
輸出:
John - 20
Jane - 21
Sara - 21
Greg - 35
people.stream()
.min(Person::ageDifference)
.ifPresent(p -> System.out.println("Youngest: " + p)); // Youngest: John - 20
people.stream()
.max(Person::ageDifference)
.ifPresent(p -> System.out.println("Eldest: " + p)); // Eldest: Greg - 35
min/max 返回 Optional,避免空指針,配合 ifPresent 安全消費。
| 方法 | 說明 | 示例 |
|---|---|---|
| comparing(keyExtractor) | 按提取鍵自然順序 | comparing(Person::getName) |
| comparing(keyExtractor, keyComparator) | 按提取鍵自定義比較器 | comparing(Person::getAge, Comparator.reverseOrder()) |
| comparingInt/Long/Double(keyExtractor) | 基本類型專用,避免裝箱 | comparingInt(Person::getAge) |
| thenComparing(...) | 次級比較器 | comparingInt(Person::getAge).thenComparing(Person::getName) |
| reversed() | 反轉順序 | byAge.reversed() |
| nullsFirst/Last(comparator) | 空值優先/靠後 | nullsFirst(comparing(Person::getName)) |
Java 8 將 Comparator 升級為函數式接口,配合 comparing、thenComparing、reversed 等默認方法,構建出強大的比較器 DSL。配合 Stream sorted、min、max,排序與極值查找代碼既極簡又類型安全。下一篇將深入 Collectors 進階聚合技巧。