ArrayList 是最高頻集合,排序是必備操作。本文涵蓋 自然序、定製序、多字段組合、降序、Java 8+ Lambda/Stream 五大場景,附完整可運行代碼。
List<String> countries = Arrays.asList("France", "USA", "India", "Spain", "England");
Collections.sort(countries); // 升序 [England, France, India, Spain, USA]
Collections.sort(countries, Collections.reverseOrder()); // 降序
原理:String 實現 Comparable<String>,按字典序比較。
public class JobCandidate implements Comparable<JobCandidate> {
private String name, gender;
private int age;
// 構造器、Getter、toString 省略
@Override
public int compareTo(JobCandidate o) {
// 年齡升序:避免減法溢出,用三元表達式
return Integer.compare(this.age, o.age);
}
}
// 使用
List<JobCandidate> list = ...;
Collections.sort(list); // 按年齡升序
限制:類內部只能定義一種自然序,修改需改動源碼。
public class JobCandidate {
private String name, gender;
private int age;
// ...
// 靜態工廠:年齡降序
public static final Comparator<JobCandidate> BY_AGE_DESC =
Comparator.comparingInt(JobCandidate::getAge).reversed();
// 靜態工廠:姓名升序
public static final Comparator<JobCandidate> BY_NAME_ASC =
Comparator.comparing(JobCandidate::getName);
}
// 使用
Collections.sort(list, JobCandidate.BY_AGE_DESC);
Collections.sort(list, JobCandidate.BY_NAME_ASC);
優勢:策略外置、可組合、不侵入實體類、支持鏈式組合(thenComparing)。
Comparator<JobCandidate> multi =
Comparator.comparingInt(JobCandidate::getAge)
.thenComparing(JobCandidate::getName, Comparator.reverseOrder());
Collections.sort(list, multi);
// 原地排序
list.sort(Comparator.comparingInt(JobCandidate::getAge).reversed());
// Stream 生成新列表(不改動原列表)
List<JobCandidate> sorted = list.stream()
.sorted(Comparator.comparing(JobCandidate::getName))
.collect(Collectors.toList());
| 場景 | 推薦方式 | 複雜度 |
|---|---|---|
| 基本類型/String/包裝類 | Collections.sort / list.sort | O(n log n) |
| 實體類單一自然序 | 實現 Comparable | O(n log n) |
| 多策略/第三方類/多字段 | Comparator 靜態常量 + 鏈式 | O(n log n) |
| 需保留原列表/鏈式處理 | Stream.sorted | O(n log n) + 額外空間 |
a - b 可能溢出,用 Integer.compare(a,b) 或 Comparator.comparingInt。Collections.sort 要求列表可變,Arrays.asList 返回固定長度列表會拋 UnsupportedOperationException,需 new ArrayList<>(Arrays.asList(...))。CopyOnWriteArrayList 快照排序。Arrays.parallelSort(Java 8+)。默認用 Comparator 靜態工廠 + 方法引用,代碼最乾淨、擴展性最強。Comparable 僅用於實體類確有「自然業務序」時。Java 8+ 讓排序代碼變成了可讀的業務語句。