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

Java List 排序完全指南:Comparable、Comparator、Lambda 與 Stream 實戰

     編輯:Java 綜合教學

Java List 排序完全指南:Comparable、Comparator、Lambda 與 Stream 實戰

Collections.sort 與 List.sort 是 Java 集合排序的雙引擎。本文系統對比自然排序與定製排序、匿名內部類與 Lambda 表達式、舊 API 與 Stream 流式排序,提供生產環境選型標準。

兩大核心 API 對比

API適用場景特點
Collections.sort(list)元素實現 Comparable靜態工具方法,修改原列表
Collections.sort(list, comparator)需定製排序邏輯策略模式,靈活複用
list.sort(comparator)Java 8+ 首選默認方法,支援並行排序 parallelSort
list.stream().sorted(...).collect()函數式管道、需保留原列表產生新列表,可鏈式組合

方案一:實現 Comparable 自然排序(侵入式)

public class Person implements Comparable {
    private String name;
    private Integer order; // 排序鍵

    // Getter/Setter 省略

    @Override
    public int compareTo(Person other) {
        // 空值安全:將 null 視為最小
        return Comparator.nullsFirst(Comparator.naturalOrder())
                         .compare(this.order, other.order);
    }
}

// 使用
List list = Arrays.asList(p2, p1, p3);
Collections.sort(list); // 或 list.sort(null)
// 輸出: name1(order=1), name2(order=2), name3(order=3)

優點: 語義清晰,無需外部比較器。缺點: 修改實體類,只能有一種自然順序。

方案二:Comparator 定製排序(非侵入式,推薦)

1. 匿名內部類(Java 7 風格)

Collections.sort(list, new Comparator() {
    @Override public int compare(Person p1, Person p2) {
        return p1.getOrder().compareTo(p2.getOrder());
    }
});

2. Lambda 表達式(Java 8+ 標準)

// 升序
list.sort(Comparator.comparing(Person::getOrder));

// 降序
list.sort(Comparator.comparing(Person::getOrder).reversed());

// 多鍵排序:先按 order 升序,再按 name 降序
list.sort(Comparator
    .comparing(Person::getOrder)
    .thenComparing(Person::getName, Comparator.reverseOrder()));

// 空值安全:null 排最後
list.sort(Comparator.comparing(Person::getOrder, 
    Comparator.nullsLast(Comparator.naturalOrder())));

方案三:Stream 流式排序(不可變、鏈式)

List sorted = list.stream()
    .filter(p -> p.getOrder() != null)
    .sorted(Comparator.comparing(Person::getOrder))
    .collect(Collectors.toList());

// 並行排序(大數據量)
List parallelSorted = list.parallelStream()
    .sorted(Comparator.comparing(Person::getOrder))
    .collect(Collectors.toList());

進階技巧:比較器組合與工廠方法

// 靜態導入簡化代碼
import static java.util.Comparator.*;

// 反轉
Comparator desc = comparing(Person::getOrder).reversed();

// 空值處理
Comparator nullsFirst = nullsFirst(naturalOrder());
Comparator nullsLast  = nullsLast(comparing(Person::getOrder));

// 比較器鏈
Comparator complex = comparing(Person::getOrder)
    .thenComparing(Person::getName, String::compareToIgnoreCase)
    .thenComparing(Person::getAge, nullsLast(naturalOrder()));

// 基於鍵提取器的比較器(避免重複獲取屬性)
Comparator byOrder = comparingInt(Person::getOrder); // 基本類型專用,無裝箱

性能與選型建議

場景推薦方案理由
實體類穩定、單一業務排序Comparable語義內聚,零額外代碼
多種排序需求、不修改實體Comparator.comparing策略模式,靈活組合
需保留原列表、函數式管道Stream.sorted不可變,易測試
超大列表(>10萬)、多核 CPUparallelStream().sorted()利用 ForkJoinPool 並行
基本類型排序鍵comparingInt/Long/Double避免裝箱開銷

避坑指南

  • ❌ compareTo 中直接相減 return a - b → 整數溢出風險
  • ✅ 使用 Integer.compare(a, b) 或 Comparator.naturalOrder()
  • ❌ Comparator.comparing(p -> p.getOrder()) → 無方法引用優化
  • ✅ Comparator.comparing(Person::getOrder) → 編譯器優化為 Comparators$ComparableComparator
  • ❌ 忽略空值導致 NPE
  • ✅ 統一使用 nullsFirst/Last 明確語義

Java 8+ 時代,Comparator.comparing + 方法引用 + 鏈式組合是排序代碼的標準範式:類型安全、可讀性強、零裝箱、易並行。拋棄匿名內部類,擁抱函數式比較器。

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