(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 trong ý chính này
Sử dụng lambda's Java 8 (đã thêm ngày 10 tháng 4 năm 2019)
Java 8 giải quyết điều này một cách độc đáo bằng lambda (mặc dù Guava và Apache Commons vẫn có thể cung cấp sự 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 bên dưới .
Lộn xộn và hỗn độn: Sắp xếp 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 rất nhiều gõ, bảo trì và dễ bị lỗi.
Cách phản chiếu: Sắp xếp với BeanComparator
ComparatorChain chain = new ComparatorChain(Arrays.asList(
new BeanComparator("size"),
new BeanComparator("nrOfToppings"),
new BeanComparator("name")));
Collections.sort(pizzas, chain);
Rõ ràng điều này ngắn gọn hơn, nhưng thậm chí còn dễ bị 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 an toàn kiểu, 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 vấn đề. Hơn nữa, vì giải pháp này sử dụng sự phản chiếu, việc sắp xếp chậm hơn nhiều.
Đến đó: Sắp xếp với So sánh của Google Guava
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();
// or in case the fields can be null:
/*
return ComparisonChain.start()
.compare(p1.size, p2.size, Ordering.natural().nullsLast())
.compare(p1.nrOfToppings, p2.nrOfToppings, Ordering.natural().nullsLast())
.compare(p1.name, p2.name, Ordering.natural().nullsLast())
.result();
*/
}
});
Điều này tốt hơn nhiều, nhưng yêu cầu một số mã tấm nồi hơi cho trường hợp sử dụng phổ biến nhất: giá trị null nên được định giá ít hơn theo mặc định. Đối với các trường null, bạn phải cung cấp thêm một lệnh cho Guava phải làm gì trong trường hợp đó. Đây là một cơ chế linh hoạt nếu bạn muốn làm một cái 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).
Sắp xếp với Apache Commons So sánhToBuilder
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ư so sánh 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 cứ điều gì khác, trừ khi bạn cung cấp Trình so sánh của riêng bạn.
Như vậy
Cuối cùng, điều này dẫn đến hương vị và nhu cầu linh hoạt (so sánh của Guava) so với mã ngắn gọn (so sánh với Apache của Apache).
Phương thức thưởng
Tôi đã tìm thấy một giải pháp hay, kết hợp nhiều bộ so sánh theo thứ tự ưu tiên trên CodeReview theo 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 Bộ sưu tập Apache Commons đã được sử dụng cho việc này:
Công cụ so sánhUtils.chainedComparator (công cụ so sánh)
Collections.sort(list, ComparatorUtils.chainedComparator(comparators));