首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java List 排序兩大核心方案:Comparable 內部比較器 vs Comparator 外部策略模式

     編輯:Java 相關知識

Java 集合排序提供兩條正交路徑:實體自帶比較邏輯 (Comparable) 與 外部注入比較策略 (Comparator)。本文以 Student (姓名、年齡) 為例,完整展示兩種方案代碼、List.sort()/Collections.sort() 調用差異、多欄位排序組合、Lambda 簡寫與效能考量。

方案一:實體實作 Comparable (內部比較器)

public class Student implements Comparable<Student> {
  private String name;
  private int age;

  // 建構子、getter/setter 省略

  @Override
  public int compareTo(Student o) {
    // 1. 姓名升序
    int cmp = this.name.compareTo(o.name);
    // 2. 姓名相同,年齡升序
    if (cmp == 0) cmp = Integer.compare(this.age, o.age);
    return cmp;
  }
}

// 使用
List<Student> list = new ArrayList<>();
list.add(new Student("b", 12));
list.add(new Student("a", 10));
list.add(new Student("b", 11));
list.add(new Student("ac", 20));

list.sort(null); // 或 Collections.sort(list)
// 結果: a/10, ac/20, b/11, b/12

方案二:外部 Comparator 策略模式 (推薦、靈活)

public class Student {
  private String name;
  private int age;
  // getter/setter
}

// 單一職責 Comparator
public class StudentNameAgeComparator implements Comparator<Student> {
  @Override
  public int compare(Student o1, Student o2) {
    int cmp = o1.getName().compareTo(o2.getName());
    if (cmp == 0) cmp = Integer.compare(o1.getAge(), o2.getAge());
    return cmp;
  }
}

// 使用
list.sort(new StudentNameAgeComparator());
// 或 Lambda (Java 8+)
list.sort(Comparator.comparing(Student::getName)
                    .thenComparingInt(Student::getAge));

// 反序
list.sort(Comparator.comparing(Student::getName).reversed()
                    .thenComparingInt(Student::getAge));

核心差異對比

維度ComparableComparator
定義位置實體類內部獨立類/靜態內部類/Lambda
修改排序規則修改實體代碼 (侵入式)新增/替換 Comparator (非侵入)
多種排序共存只能有一種自然順序可定義無限種 (按姓名/年齡/註冊時間...)
適用場景單一、固定、領域核心排序多變、場景相關、第三方類無法修改
調用方式list.sort(null)list.sort(comparator)

進階:Comparator 組合技巧 (Java 8+)

// 空值安全:null 排最後
Comparator<Student> nullSafe = Comparator
    .comparing(Student::getName, Comparator.nullsLast(Comparator.naturalOrder()))
    .thenComparingInt(Student::getAge);

// 多欄位混合升降序
list.sort(Comparator
    .comparing(Student::getName)           // 姓名升序
    .thenComparing(Student::getAge, Comparator.reverseOrder()) // 年齡降序
    .thenComparing(Student::getId));       // ID 升序兜底

// 原始類型專用比較器 (避免裝箱)
.thenComparingInt(Student::getAge)
.thenComparingLong(Student::getScore)
.thenComparingDouble(Student::getRate)

效能與最佳實踐

  1. TimSort (JDK 7+):List.sort 使用 TimSort (歸併+插入混合),近乎有序數據 O(n),隨機 O(n log n),穩定排序。
  2. Comparator 複用:定義為 static final 常量或單例,避免重複創建。
  3. 基本類型用 thenComparingInt/Long/Double:避免自動裝箱開銷。
  4. 大數據量並行排序:Arrays.parallelSort(arr, comparator) (需數組,List 先 toArray)。
  5. 不可變對象:排序不修改對象狀態,確保 compareTo/compare 純函數無副作用。

總結

Comparable 定義「自然順序」,Comparator 定義「場景順序」。新代碼**優先用 Comparator + Lambda 鏈式組合** (非侵入、可讀、可組合、可測試);只有領域模型確有「唯一自然順序」語義時 (如 ID、時間戳) 才實作 Comparable。掌握 Comparator.comparing/thenComparing/nullsFirst/reverseOrder 全家桶,即能優雅解決 99% 排序需求。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved