(nguyên gốc từ Cách sắp xếp danh sách các đối tượng trong Java dựa trên nhiều trường )
Mã làm việc ban đầu trong ý chính này
Sử dụng Java 8 lambda's (thêm vào ngày 10 tháng 4 năm 2019)
Java 8 giải quyết vấn đề này một cách độc đáo nhờ lambda's (mặc dù Guava và Apache Commons vẫn có thể cung cấp tính linh hoạt hơn):
Collections.sort(reportList, Comparator.comparing(Report::getReportKey)
.thenComparing(Report::getStudentNumber)
.thenComparing(Report::getSchool));
Cảm ơn câu trả lời của @ gaoagong dưới đây .
Lưu ý rằng một lợi thế ở đây là getters được đánh giá một cách lười biếng (ví dụ: getSchool()
chỉ được đánh giá nếu có liên quan).
Lộn xộn và phức tạp: Phân loại bằng tay
Collections.sort(pizzas, new Comparator<Pizza>() {
@Override
public int compare(Pizza p1, Pizza p2) {
int sizeCmp = p1.size.compareTo(p2.size);
if (sizeCmp != 0) {
return sizeCmp;
}
int nrOfToppingsCmp = p1.nrOfToppings.compareTo(p2.nrOfToppings);
if (nrOfToppingsCmp != 0) {
return nrOfToppingsCmp;
}
return p1.name.compareTo(p2.name);
}
});
Điều này đòi hỏi nhiều đánh máy, bảo trì và dễ xảy ra lỗi. Ưu điểm duy nhất là getters chỉ được gọi khi có liên quan.
Cách phản chiếu: Sắp xếp bằng BeanComparator
ComparatorChain chain = new ComparatorChain(Arrays.asList(
new BeanComparator("size"),
new BeanComparator("nrOfToppings"),
new BeanComparator("name")));
Collections.sort(pizzas, chain);
Rõ ràng là điều này ngắn gọn hơn, nhưng thậm chí dễ xảy ra lỗi hơn khi bạn mất tham chiếu trực tiếp đến các trường bằng cách sử dụng Chuỗi thay thế (không có an toàn kiểu chữ, tự động tái cấu trúc). Bây giờ nếu một trường được đổi tên, trình biên dịch thậm chí sẽ không báo cáo sự cố. Hơn nữa, vì giải pháp này sử dụng phản xạ, nên việc sắp xếp chậm hơn nhiều.
Đến đó: Sắp xếp với Google Guava's ComparisonChain
Collections.sort(pizzas, new Comparator<Pizza>() {
@Override
public int compare(Pizza p1, Pizza p2) {
return ComparisonChain.start().compare(p1.size, p2.size).compare(p1.nrOfToppings, p2.nrOfToppings).compare(p1.name, p2.name).result();
}
});
Điều này tốt hơn nhiều, nhưng yêu cầu một số mã tấm lò hơi cho trường hợp sử dụng phổ biến nhất: giá trị null nên được đánh giá thấp hơn theo mặc định. Đối với trường null, bạn phải cung cấp thêm một chỉ thị cho Guava những việc cần làm trong trường hợp đó. Đây là một cơ chế linh hoạt nếu bạn muốn làm điều gì đó cụ thể, nhưng thường thì bạn muốn trường hợp mặc định (ví dụ: 1, a, b, z, null).
Và như đã lưu ý trong các bình luận bên dưới, những getters này đều được đánh giá ngay lập tức cho mỗi lần so sánh.
Sắp xếp với Apache Commons CompareToBuilder
Collections.sort(pizzas, new Comparator<Pizza>() {
@Override
public int compare(Pizza p1, Pizza p2) {
return new CompareToBuilder().append(p1.size, p2.size).append(p1.nrOfToppings, p2.nrOfToppings).append(p1.name, p2.name).toComparison();
}
});
Giống như ComparisonChain của Guava, lớp thư viện này sắp xếp dễ dàng trên nhiều trường, nhưng cũng xác định hành vi mặc định cho các giá trị null (ví dụ: 1, a, b, z, null). Tuy nhiên, bạn cũng không thể chỉ định bất kỳ điều gì khác, trừ khi bạn cung cấp Bộ so sánh của riêng mình.
Một lần nữa, như đã lưu ý trong các bình luận bên dưới, những getters này đều được đánh giá ngay lập tức cho mỗi lần so sánh.
Như vậy
Cuối cùng, nó phụ thuộc vào hương vị và nhu cầu về tính linh hoạt (Guava's ComparisonChain) so với mã ngắn gọn (Apache's CompareToBuilder).
Phương thức thưởng
Tôi đã tìm thấy một giải pháp tuyệt vời kết hợp nhiều trình so sánh theo thứ tự ưu tiên trên CodeReview trong một MultiComparator
:
class MultiComparator<T> implements Comparator<T> {
private final List<Comparator<T>> comparators;
public MultiComparator(List<Comparator<? super T>> comparators) {
this.comparators = comparators;
}
public MultiComparator(Comparator<? super T>... comparators) {
this(Arrays.asList(comparators));
}
public int compare(T o1, T o2) {
for (Comparator<T> c : comparators) {
int result = c.compare(o1, o2);
if (result != 0) {
return result;
}
}
return 0;
}
public static <T> void sort(List<T> list, Comparator<? super T>... comparators) {
Collections.sort(list, new MultiComparator<T>(comparators));
}
}
Tất nhiên Apache Commons Collections đã có một ứng dụng cho việc này:
ComparatorUtils.chainedComparator (bộ so sánhCollection)
Collections.sort(list, ComparatorUtils.chainedComparator(comparators));