(від способів сортування списків об'єктів на Java на основі кількох полів )
Робочий код у цій суті
Використання лямбда Java 8 (додано 10 квітня 2019 р.)
Java 8 це чудово вирішує лямбда (хоча Guava та Apache Commons все ще можуть запропонувати більшу гнучкість):
Collections.sort(reportList, Comparator.comparing(Report::getReportKey)
.thenComparing(Report::getStudentNumber)
.thenComparing(Report::getSchool));
Завдяки відповіді @ gaoagong нижче .
Брудний і перекручений: сортування вручну
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);
}
});
Для цього потрібно багато набору тексту, технічного обслуговування та схильності до помилок.
Рефлексивний спосіб: сортування за допомогою BeanComparator
ComparatorChain chain = new ComparatorChain(Arrays.asList(
new BeanComparator("size"),
new BeanComparator("nrOfToppings"),
new BeanComparator("name")));
Collections.sort(pizzas, chain);
Очевидно, це більш стисло, але ще більше схильності до помилок, оскільки ви втрачаєте пряме посилання на поля, використовуючи натомість Strings (відсутність безпеки, автоматичне відновлення). Тепер, якщо поле перейменовано, компілятор навіть не повідомить про проблему. Більше того, оскільки це рішення використовує рефлексію, сортування відбувається набагато повільніше.
Як дістатися: сортування за допомогою Google Guava's ComparingChain
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();
*/
}
});
Це набагато краще, але вимагає деякого коду пластини котла для найпоширенішого випадку використання: нульові значення повинні бути оцінені за замовчуванням менше. Для нульових полів ви повинні надати додатковій інструкції Гуаві, що робити в такому випадку. Це гнучкий механізм, якщо ви хочете зробити щось конкретне, але часто вам потрібен випадок за замовчуванням (тобто 1, a, b, z, null).
Сортування за допомогою 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();
}
});
Як і Guava's ComparingChain, цей клас бібліотеки легко сортує по декількох полях, але також визначає поведінку за замовчуванням для нульових значень (тобто 1, a, b, z, null). Однак ви також не можете вказати нічого іншого, якщо ви не надасте власний компаратор.
Таким чином
Зрештою, це зводиться до смаку та потреби у гнучкості (Guava's ComparingChain) проти стислого коду (Apache's CompareToBuilder).
Бонусний метод
Я знайшов хороше рішення, яке поєднує в собі декілька компараторів у порядку пріоритетності в CodeReview у 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));
}
}
Звичайно, Apache Commons Collection має для цього корисну програму:
ComparatorUtils.chainedComparator (comparatorCollection)
Collections.sort(list, ComparatorUtils.chainedComparator(comparators));