- 1 1. Những Điều Bạn Sẽ Học Trong Bài Viết Này (Cách Nhanh Nhất Để Sắp Xếp Một Java List)
- 2 2. Ba Cách Thông Dụng Để Sắp Xếp Một List Trong Java (Bạn Nên Dùng Cách Nào?)
- 3 3. Sắp xếp cơ bản: Thứ tự tăng và giảm
- 4 4. Sắp xếp List các đối tượng: Hiểu về Comparator
- 5 5. Sắp xếp với nhiều điều kiện (Mẫu thực tế phổ biến nhất)
- 6 6. Xử lý Giá trị null An toàn (Một Nguồn Lỗi Rất Thường Gặp)
- 7 7. Các Cạm Bẫy và Sai Lầm Thông Thường (Cách Tránh Các Lỗi Nhỏ Nhặt)
- 8 8. Các cân nhắc về hiệu năng và chọn cách tiếp cận đúng
- 9 9. Summary: Java List Sort Cheat Sheet
1. Những Điều Bạn Sẽ Học Trong Bài Viết Này (Cách Nhanh Nhất Để Sắp Xếp Một Java List)
Khi làm việc với Java, rất thường xuyên bạn sẽ gặp phải các tình huống cần sắp xếp một List.
Cùng lúc đó, nhiều lập trình viên—đặc biệt là người mới—thường bối rối với những câu hỏi như:
- Tôi nên dùng phương thức nào để sắp xếp một List?
- Sự khác nhau giữa
list.sort()vàCollections.sort()là gì? - Làm sao để sắp xếp một List các đối tượng thay vì các giá trị đơn giản?
Bài viết này được thiết kế để trả lời những câu hỏi một cách rõ ràng và thực tiễn, bắt đầu bằng kết luận, sau đó dần dần giải thích chi tiết và các trường hợp sử dụng thực tế.
1.1 Kết Luận: Đây Là Mẫu Đơn Giản Nhất Bạn Cần Nhớ
Nếu bạn chỉ muốn cách ngắn gọn và chuẩn nhất để sắp xếp một List trong Java, thì đây là nó:
list.sort(Comparator.naturalOrder());
Điều này sẽ sắp xếp List theo thứ tự tăng dần (nhỏ nhất tới lớn nhất, A tới Z, cũ nhất tới mới nhất).
Nếu bạn muốn theo thứ tự giảm dần, hãy dùng đoạn này thay thế:
list.sort(Comparator.reverseOrder());
Chỉ với hai dòng này, bạn đã có thể sắp xếp các List của:
IntegerStringLocalDate- và hầu hết các kiểu dữ liệu phổ biến khác
Đối với nhiều trường hợp hàng ngày, đây là tất cả những gì bạn cần.
1.2 Sắp Xếp List Các Đối Tượng: Xác Định Khóa Sắp Xếp
Trong các ứng dụng thực tế, List thường chứa các đối tượng, không phải các giá trị đơn giản.
Ví dụ:
class Person {
private String name;
private int age;
// getters omitted
}
Để sắp xếp một List<Person> theo tuổi, viết như sau:
list.sort(Comparator.comparing(Person::getAge));
Dòng duy nhất này có nghĩa là:
- Lấy
agetừ mỗiPerson - So sánh các giá trị đó
- Sắp xếp List theo thứ tự tăng dần
Bạn không cần tự viết logic so sánh.
Chỉ cần nhớ mẫu này:
Comparator.comparing(whatToCompare)
1.3 Nội Dung Bài Viết
Bài viết giải thích cách sắp xếp Java List từ cơ bản đến thực tiễn, bao gồm:
- Sự khác nhau giữa
list.sort()vàCollections.sort() - Cách hoạt động của
Comparatormột cách đơn giản - Sắp xếp với nhiều điều kiện (ví dụ: tuổi → tên)
- Kết hợp thứ tự tăng và giảm
- Xử lý an toàn các giá trị
null - Khi nào nên dùng
stream().sorted()thay vìlist.sort()
Mục tiêu không phải ghi nhớ, mà là hiểu tại sao mỗi cách lại tồn tại.
1.4 Đối Tượng Đọc Bài Viết
Bài viết này dành cho các lập trình viên mà:
- Hiểu cú pháp cơ bản của Java (lớp, phương thức, List)
- Đã từng dùng
ArrayListhoặcList - Vẫn phải tra cứu mã sắp xếp mỗi khi cần
Nó không hướng tới những người hoàn toàn mới chưa từng viết mã Java,
nhưng có thân thiện với người mới bắt đầu muốn học lập trình Java thực tế.
2. Ba Cách Thông Dụng Để Sắp Xếp Một List Trong Java (Bạn Nên Dùng Cách Nào?)
Trong Java, không chỉ có một cách duy nhất để sắp xếp một List.
Trong thực tế, các lập trình viên chủ yếu dùng ba phương pháp khác nhau, mỗi phương pháp có hành vi và mục đích hơi khác nhau.
Trước khi đi sâu vào Comparator, quan trọng là phải hiểu khi nào và tại sao mỗi tùy chọn tồn tại.
2.1 list.sort(Comparator) — Cách Hiện Đại và Được Đề Xuất
Kể từ Java 8, đây là cách chuẩn và được khuyến nghị nhất để sắp xếp một List.
list.sort(Comparator.naturalOrder());
Đặc điểm chính
- Được định nghĩa trực tiếp trên giao diện
List - Rõ ràng và dễ đọc
- Sắp xếp List gốc tại chỗ (destructive)
Sắp xếp các đối tượng cũng hoạt động tương tự:
list.sort(Comparator.comparing(Person::getAge));
Khi nào nên dùng
- Khi bạn đồng ý việc List gốc sẽ bị thay đổi
- Khi bạn muốn giải pháp rõ ràng và đơn giản nhất
👉 Nếu bạn không chắc, list.sort() thường là lựa chọn đúng.
2.2 Collections.sort(list) — Kiểu Cũ Bạn Vẫn Cần Nhận Biết
Bạn có thể thấy mã như sau trong các tutorial cũ hoặc dự án legacy:
Collections.sort(list);
Hoặc với một Comparator:
Collections.sort(list, Comparator.reverseOrder());
Đặc điểm chính
- Có từ Java 1.2
- Nội bộ hoạt động gần như tương tự
list.sort - Cũng thay đổi List gốc
Tại sao nó ít được dùng hiện nay
- Java 8 đã giới thiệu
list.sort, cảm giác tự nhiên hơn - Sắp xếp List bằng
Collectionsít trực quan hơn
Đối với mã mới, list.sort được ưu tiên.
Tuy nhiên, việc hiểu Collections.sort vẫn quan trọng khi đọc các codebase cũ.
2.3 stream().sorted() — Sắp xếp không phá hủy
Tùy chọn thứ ba sử dụng Stream API.
List<Integer> sorted =
list.stream()
.sorted()
.toList();
Với một Comparator:
List<Person> sorted =
list.stream()
.sorted(Comparator.comparing(Person::getAge))
.toList();
Đặc điểm chính
- KHÔNG thay đổi List gốc
- Trả về một List mới đã được sắp xếp
- Dễ dàng kết hợp với
filter,map, và các thao tác stream khác
Khi nào nên dùng
- Khi bạn phải giữ List gốc không thay đổi
- Khi sắp xếp là một phần của pipeline xử lý dữ liệu
Đối với sắp xếp đơn giản, list.sort thường rõ ràng và hiệu quả hơn.
2.4 Cách chọn (Hướng dẫn quyết định nhanh)
| Goal | Recommended Method |
|---|---|
| Sort a List directly | list.sort() |
| Understand or maintain old code | Collections.sort() |
| Keep the original List unchanged | stream().sorted() |
Ở thời điểm này, hãy nhớ một quy tắc duy nhất:
Sử dụng
list.sort()trừ khi bạn có lý do rõ ràng để không dùng.
3. Sắp xếp cơ bản: Thứ tự tăng và giảm
Bây giờ bạn đã biết phương pháp sắp xếp nào cần dùng, hãy tập trung vào yêu cầu phổ biến nhất:
sắp xếp tăng hoặc giảm.
Phần này đề cập đến các List của các kiểu dữ liệu cơ bản như số, chuỗi và ngày—nền tảng cho mọi thứ tiếp theo.
3.1 Sắp xếp tăng dần (Thứ tự tự nhiên)
Nhiều kiểu Java có thứ tự tự nhiên, chẳng hạn như:
- Số → từ nhỏ tới lớn
- Chuỗi → thứ tự bảng chữ cái (A đến Z)
- Ngày → từ cũ tới mới
Để sắp xếp một List tăng dần, dùng:
list.sort(Comparator.naturalOrder());
Ví dụ: Sắp xếp số
List<Integer> numbers = Arrays.asList(5, 1, 3, 2);
numbers.sort(Comparator.naturalOrder());
Kết quả:
[1, 2, 3, 5]
Ví dụ: Sắp xếp chuỗi
List<String> names = Arrays.asList("Tom", "Alice", "Bob");
names.sort(Comparator.naturalOrder());
Kết quả:
[Alice, Bob, Tom]
👉 Nếu bạn chỉ muốn thứ tự tăng, đây là cách đơn giản và an toàn nhất.
3.2 Sắp xếp giảm dần
Để đảo ngược thứ tự tự nhiên, dùng Comparator.reverseOrder().
list.sort(Comparator.reverseOrder());
Ví dụ: Số giảm dần
List<Integer> numbers = Arrays.asList(5, 1, 3, 2);
numbers.sort(Comparator.reverseOrder());
Kết quả:
[5, 3, 2, 1]
Ví dụ: Chuỗi giảm dần
List<String> names = Arrays.asList("Tom", "Alice", "Bob");
names.sort(Comparator.reverseOrder());
Kết quả:
[Tom, Bob, Alice]
3.3 Khi có thể bỏ qua Comparator
Trong một số trường hợp, bạn có thể thấy mã sắp xếp được viết mà không có Comparator rõ ràng.
Collections.sort(list);
Hoặc thậm chí:
list.sort(null);
Các cách này chỉ hoạt động nếu:
- Các phần tử triển khai
Comparable - Bạn muốn thứ tự tự nhiên (tăng dần)
Mặc dù hợp lệ, các kiểu này ít rõ ràng hơn.
Trong các codebase thực tế, phiên bản này thường được ưu tiên vì tính rõ ràng:
list.sort(Comparator.naturalOrder());
3.4 Hiểu lầm phổ biến: Ai quyết định thứ tự?
Một nguồn gây nhầm lẫn thường gặp cho người mới là nghĩ rằng:
sort()quyết định thứ tự tăng hay giảm
Thực tế:
sort()thực hiện việc sắp xếpComparatorxác định cách các phần tử được so sánh
Khi bạn hiểu được sự tách biệt này,
mọi thứ khác—sắp xếp đối tượng, nhiều điều kiện, và xử lý null—sẽ trở nên dễ dàng hơn rất nhiều.
4. Sắp xếp List các đối tượng: Hiểu về Comparator
Trong các ứng dụng Java thực tế, bạn hiếm khi sắp xếp các giá trị đơn giản như Integer hay String.
Hầu hết thời gian, bạn sẽ sắp xếp Danh sách các đối tượng tùy chỉnh.
Đây là nơi Comparator trở thành khái niệm cốt lõi.
4.1 Comparator là gì?
Một Comparator định nghĩa cách hai phần tử nên được so sánh.
Về mặt khái niệm, nó trả lời câu hỏi:
“Cho hai đối tượng, đối tượng nào nên đứng trước?”
Bên trong, một Comparator trả về:
- Một số âm → phần tử đầu tiên đứng trước
- Số 0 → thứ tự không quan trọng
- Một số dương → phần tử thứ hai đứng trước
May mắn là trong Java hiện đại bạn hầu như không cần tự viết logic này bằng tay.
4.2 Sắp xếp theo một trường bằng Comparator.comparing
Xem xét lớp sau:
class Person {
private String name;
private int age;
// getters omitted
}
Để sắp xếp một List<Person> theo tuổi, dùng:
list.sort(Comparator.comparing(Person::getAge));
Cách này đọc một cách tự nhiên:
- Lấy từng
Person - Trích xuất
age - So sánh các giá trị đó
- Sắp xếp List theo thứ tự tăng dần
Một dòng duy nhất này thay thế nhiều dòng code so sánh cũ.
4.3 Sắp xếp theo String, Date và các kiểu khác
Mẫu tương tự hoạt động cho hầu hết mọi kiểu trường.
Sắp xếp theo tên
list.sort(Comparator.comparing(Person::getName));
Sắp xếp theo ngày
list.sort(Comparator.comparing(Person::getBirthDate));
Miễn là giá trị được trích xuất có thứ tự tự nhiên,
Comparator.comparing sẽ hoạt động mà không cần cấu hình thêm.
4.4 Sử dụng Comparator chuyên cho các kiểu nguyên thủy
Đối với các trường số, Java cung cấp các phương thức tối ưu:
comparingIntcomparingLongcomparingDouble
Ví dụ:
list.sort(Comparator.comparingInt(Person::getAge));
Các phương thức này:
- Tránh việc đóng gói đối tượng không cần thiết
- Làm cho ý định của bạn rõ ràng hơn
- Hơi hiệu quả hơn đối với các List lớn
Mặc dù sự khác biệt là nhỏ, chúng được coi là thực hành tốt cho các trường số.
4.5 Tại sao điều này quan trọng
Khi bạn hiểu Comparator.comparing, bạn sẽ mở khóa:
- Sắp xếp đa điều kiện
- Kết hợp thứ tự tăng và giảm
- Xử lý an toàn các giá trị
null
Nói cách khác, đây là nền tảng của việc sắp xếp List thực tế trong Java.
5. Sắp xếp với nhiều điều kiện (Mẫu thực tế phổ biến nhất)
Trong các ứng dụng thực tế, sắp xếp chỉ theo một trường thường không đủ.
Bạn thường cần các điều kiện phụ và thứ ba để tạo ra một thứ tự ổn định và có ý nghĩa.
Các ví dụ bao gồm:
- Sắp xếp theo tuổi, rồi theo tên
- Sắp xếp theo mức ưu tiên, rồi theo thời gian
- Sắp xếp theo điểm (giảm dần), rồi theo ID (tăng dần)
API Comparator của Java được thiết kế riêng cho mục đích này.
5.1 Cơ bản về thenComparing
Sắp xếp đa điều kiện tuân theo một quy tắc đơn giản:
Nếu hai phần tử bằng nhau theo điều kiện đầu tiên, dùng điều kiện tiếp theo.
Đây là mẫu cơ bản:
list.sort(
Comparator.comparingInt(Person::getAge)
.thenComparing(Person::getName)
);
Nghĩa là:
- Sắp xếp theo
age(tăng dần) - Nếu tuổi bằng nhau, sắp xếp theo
name(tăng dần)
Kết quả là một thứ tự nhất quán và dự đoán được.
5.2 Kết hợp thứ tự tăng và giảm
Rất thường xuyên, bạn muốn một trường sắp xếp giảm dần và trường khác tăng dần.
Ví dụ: Điểm (giảm dần), Tên (tăng dần)
list.sort(
Comparator.comparingInt(Person::getScore).reversed()
.thenComparing(Person::getName)
);
Chi tiết quan trọng:
reversed()chỉ áp dụng cho Comparator ngay trước nó
Điều này giúp bạn kết hợp an toàn các hướng sắp xếp khác nhau.
5.3 Truyền Comparator vào thenComparing
Để mã dễ đọc hơn, bạn có thể xác định rõ hướng sắp xếp bên trong thenComparing.
Ví dụ: Tuổi (tăng dần), Ngày đăng ký (giảm dần)
list.sort(
Comparator.comparingInt(Person::getAge)
.thenComparing(
Comparator.comparing(Person::getRegisterDate).reversed()
)
);
Kiểu này làm cho việc xác định trường nào tăng dần hay giảm dần trở nên rất rõ ràng, điều này hữu ích cho việc xem xét mã và bảo trì lâu dài.
5.4 Ví dụ Kinh doanh Thực tế
list.sort(
Comparator.comparingInt(Order::getPriority)
.thenComparing(Order::getDeadline)
.thenComparing(Order::getOrderId)
);
Logic sắp xếp:
- Ưu tiên cao hơn trước
- Hạn chót sớm hơn trước
- ID đơn hàng thấp hơn trước
Điều này đảm bảo một thứ tự ổn định và thân thiện với kinh doanh.

5.5 Giữ cho Việc Sắp xếp Nhiều Điều kiện Dễ đọc
Khi logic sắp xếp phát triển, khả năng đọc hiểu trở nên quan trọng hơn so với độ ngắn gọn.
Các thực hành tốt nhất:
- Tách dòng cho mỗi điều kiện
- Tránh các lambda lồng nhau sâu
- Thêm chú thích nếu các quy tắc kinh doanh không rõ ràng
Logic sắp xếp rõ ràng tiết kiệm thời gian cho mọi người đọc mã sau này.
6. Xử lý Giá trị null An toàn (Một Nguồn Lỗi Rất Thường Gặp)
Khi sắp xếp dữ liệu thực tế, giá trị null hầu như không thể tránh được. Các trường có thể là tùy chọn, dữ liệu cũ có thể không đầy đủ, hoặc giá trị có thể đơn giản là thiếu.
Nếu bạn không xử lý null một cách rõ ràng, việc sắp xếp có thể dễ dàng thất bại khi chạy.
6.1 Tại sao null Gây Vấn đề Khi Sắp xếp
Xem xét đoạn mã này:
list.sort(Comparator.comparing(Person::getName));
Nếu getName() trả về null cho bất kỳ phần tử nào, Java sẽ ném ra NullPointerException trong quá trình so sánh.
Điều này xảy ra vì:
- Một
Comparatorgiả định các giá trị có thể so sánh được nullkhông có thứ tự tự nhiên trừ khi bạn định nghĩa một thứ tự
Do đó, việc xử lý null phải được thực hiện một cách rõ ràng.
6.2 Sử dụng nullsFirst và nullsLast
Java cung cấp các phương thức trợ giúp để định nghĩa cách sắp xếp các giá trị null.
Đặt giá trị null lên đầu
list.sort(
Comparator.comparing(
Person::getName,
Comparator.nullsFirst(Comparator.naturalOrder())
)
);
Đặt giá trị null xuống cuối
list.sort(
Comparator.comparing(
Person::getName,
Comparator.nullsLast(Comparator.naturalOrder())
)
);
Các cách tiếp cận này:
- Ngăn ngừa
NullPointerException - Làm cho quy tắc sắp xếp rõ ràng và dễ đọc
6.3 Khi Danh sách Bản thân Chứa Các Phần tử null
Đôi khi, các phần tử của Danh sách có thể là null.
List<Person> list = Arrays.asList(
new Person("Alice", 20),
null,
new Person("Bob", 25)
);
Để xử lý điều này một cách an toàn:
list.sort(
Comparator.nullsLast(
Comparator.comparing(Person::getName)
)
);
Điều này đảm bảo:
- Các phần tử
nullđược chuyển đến cuối danh sách - Các phần tử không phải
nullđược sắp xếp bình thường
6.4 Cẩn thận với comparingInt và null
Các comparator đặc thù cho kiểu nguyên thủy như comparingInt không thể xử lý null.
Comparator.comparingInt(Person::getAge); // age must be int
Nếu trường là một Integer có thể là null, hãy sử dụng:
Comparator.comparing(
Person::getAge,
Comparator.nullsLast(Integer::compare)
);
Điều này tránh các lỗi thời gian chạy không mong muốn.
6.5 Xem việc Xử lý null như một Phần của Đặc tả
Quyết định liệu các giá trị null có nên xuất hiện:
- Ở đầu
- Ở cuối
- Hoặc được lọc bỏ hoàn toàn
đó là một quyết định kinh doanh, không chỉ là một quyết định kỹ thuật.
Bằng cách sử dụng nullsFirst hoặc nullsLast, bạn ghi lại quyết định đó trực tiếp trong mã— làm cho logic sắp xếp của bạn an toàn hơn và dễ hiểu hơn.
7. Các Cạm Bẫy và Sai Lầm Thông Thường (Cách Tránh Các Lỗi Nhỏ Nhặt)
Việc sắp xếp một List trong Java trông đơn giản, nhưng có một số cạm bẫy dễ bỏ qua có thể dẫn đến lỗi, hành vi không mong đợi hoặc vấn đề hiệu năng.
Hiểu trước những điều này sẽ tiết kiệm thời gian của bạn trong quá trình gỡ lỗi và xem xét mã.
7.1 Quên Rằng Việc Sắp xếp Là Hành Động Phá Hủy
Cả list.sort() và Collections.sort() sửa đổi List gốc.
List<Integer> original = new ArrayList<>(List.of(3, 1, 2));
List<Integer> alias = original;
original.sort(Comparator.naturalOrder());
Trong trường hợp này:
originalđược sắp xếpaliascũng được sắp xếp (vì chúng tham chiếu cùng một List)
Cách tránh điều này
Nếu bạn cần giữ nguyên thứ tự gốc:
List<Integer> sorted = new ArrayList<>(original);
sorted.sort(Comparator.naturalOrder());
Hoặc sử dụng streams:
List<Integer> sorted =
original.stream()
.sorted()
.toList();
Luôn tự hỏi mình:
“Có nên sửa đổi List gốc không?”
7.2 Tính nhất quán của Comparator và thứ tự ổn định
Một Comparator nên tạo ra kết quả nhất quán và dự đoán được.
Ví dụ:
Comparator.comparing(Person::getAge);
Nếu nhiều người có cùng tuổi, thứ tự tương đối của chúng không được xác định.
Điều này có thể chấp nhận được—nhưng thường không.
Thực hành tốt nhất
Thêm một điều kiện phụ để ổn định thứ tự:
Comparator.comparingInt(Person::getAge)
.thenComparing(Person::getId);
Điều này đảm bảo kết quả sắp xếp là quyết định được.
7.3 Phân biệt chữ hoa/chữ thường trong sắp xếp String
Thứ tự tự nhiên của String là phân biệt chữ hoa/chữ thường.
List<String> list = List.of("apple", "Banana", "orange");
list.sort(Comparator.naturalOrder());
Điều này có thể tạo ra kết quả không trực quan.
Sắp xếp không phân biệt chữ hoa/chữ thường
list.sort(String.CASE_INSENSITIVE_ORDER);
Trước khi chọn, hãy cân nhắc:
- Đây có phải để hiển thị không?
- Hoặc cho logic nội bộ?
Câu trả lời sẽ quyết định cách tiếp cận đúng.
7.4 Thực hiện công việc nặng trong Comparator
Một Comparator có thể được gọi nhiều lần trong quá trình sắp xếp.
Tránh:
- Truy cập cơ sở dữ liệu
- Gọi mạng
- Các phép tính tốn kém
// Bad idea (conceptual example) Comparator.comparing(p -> expensiveOperation(p));
Cách tiếp cận tốt hơn
- Tính trước các giá trị
- Lưu chúng trong các trường
- So sánh các giá trị đơn giản, rẻ tiền
Comparator hiệu quả tạo ra sự khác biệt lớn với các List lớn.
7.5 Ưu tiên tính dễ đọc hơn sự khéo léo
Logic sắp xếp thường được đọc nhiều hơn số lần nó được viết.
Thay vì:
- Một biểu thức chuỗi dài
- Các lambda lồng nhau sâu
Ưu tiên:
- Ngắt dòng
- Cấu trúc rõ ràng
- Các chú thích tùy chọn cho quy tắc nghiệp vụ
Mã sắp xếp dễ đọc giảm lỗi và làm cho việc bảo trì dễ dàng hơn.
8. Các cân nhắc về hiệu năng và chọn cách tiếp cận đúng
Bây giờ, bạn đã biết cách sắp xếp List trong Java.
Phần này tập trung vào cách nào nên chọn từ góc độ hiệu năng và thiết kế.
Trong hầu hết các ứng dụng, sắp xếp không phải là nút thắt—nhưng các lựa chọn sai vẫn có thể gây ra chi phí không cần thiết.
8.1 list.sort() vs stream().sorted()
Đây là điểm quyết định phổ biến nhất.
list.sort()
list.sort(Comparator.comparingInt(Person::getAge));
Ưu điểm
- Không cần cấp phát List mới
- Ý định rõ ràng: “sắp xếp List này”
- Hiệu quả hơn một chút
Nhược điểm
- Sửa đổi List gốc
stream().sorted()
List<Person> sorted =
list.stream()
.sorted(Comparator.comparingInt(Person::getAge))
.toList();
Ưu điểm
- List gốc vẫn không thay đổi
- Phù hợp tự nhiên vào các pipeline stream
Nhược điểm
- Cấp phát một List mới
- Một chút chi phí hơn
Quy tắc thực tế
- Sắp xếp đơn giản →
list.sort() - Pipeline chuyển đổi hoặc tính bất biến →
stream().sorted()
8.2 Sắp xếp List lớn một cách hiệu quả
Thuật toán sắp xếp gọi Comparator nhiều lần. Đối với List lớn, điều này quan trọng.
Hướng dẫn chính
- Giữ comparator nhẹ
- Tránh chuỗi phương thức thực hiện công việc nặng
- Ưu tiên comparator nguyên thủy (
comparingInt, v.v.)
Ví dụ: Tính trước các khóa tốn kém
Thay vì:
Comparator.comparing(p -> calculateScore(p));
Thực hiện:
// Precompute once
p.setScore(calculateScore(p));
Sau đó sắp xếp theo trường:
Comparator.comparingInt(Person::getScore);
Điều này giảm đáng kể công việc lặp lại trong quá trình sắp xếp.
8.3 Collections.sort() Có Bao Giờ Là Lựa Chọn Đúng?
Đối với mã mới, hầu như không bao giờ.
Tuy nhiên, nó vẫn xuất hiện trong:
- Các dự án kế thừa
- Các hướng dẫn cũ
- Các codebase Java 7 và trước đó
Bạn không cần phải sử dụng nó—nhưng bạn nên nhận ra nó.
8.4 Recommended Decision Checklist
Trước khi sắp xếp, hãy hỏi:
- Tôi có thể sửa đổi List gốc không?
- Tôi có cần nhiều điều kiện sắp xếp không?
- Có trường nào có thể là
nullkhông? - Hiệu năng có quan trọng khi quy mô lớn không?
Trả lời những câu hỏi này sẽ tự nhiên dẫn đến giải pháp đúng.
9. Summary: Java List Sort Cheat Sheet
Hãy tổng hợp mọi thứ thành một hướng dẫn tham khảo nhanh mà bạn có thể tin cậy.
9.1 Quick Patterns You’ll Use Most Often
Ascending order
list.sort(Comparator.naturalOrder());
Descending order
list.sort(Comparator.reverseOrder());
9.2 Sorting Objects by a Field
list.sort(Comparator.comparing(Person::getName));
For numbers:
list.sort(Comparator.comparingInt(Person::getAge));
9.3 Multiple Conditions
list.sort(
Comparator.comparingInt(Person::getAge)
.thenComparing(Person::getName)
);
Mixed order:
list.sort(
Comparator.comparingInt(Person::getScore).reversed()
.thenComparing(Person::getName)
);
9.4 Safe null Handling
list.sort(
Comparator.comparing(
Person::getName,
Comparator.nullsLast(Comparator.naturalOrder())
)
);
List may contain null elements:
list.sort(
Comparator.nullsLast(
Comparator.comparing(Person::getName)
)
);
9.5 Non-Destructive Sorting
List<Person> sorted =
list.stream()
.sorted(Comparator.comparingInt(Person::getAge))
.toList();
9.6 Final Takeaway
Java List sorting becomes simple once you remember:
Comparatorxác định thứ tựsort()thực hiện thao tác- Rõ ràng thắng hơn sự khéo léo
- Xử lý
nullmột cách rõ ràng ngăn ngừa lỗi
Nếu bạn nắm vững những nguyên tắc này,
Bạn sẽ không bao giờ cần “học lại” việc sắp xếp List trong Java nữa.

