(родом із « Способи сортування списків об’єктів у Java» на основі декількох полів )
Оригінальний робочий код у цій суті
Використання лямбда-сигналів Java 8 (додано 10 квітня 2019 р.)
Java 8 добре вирішує це за допомогою лямбда-процесів (хоча Guava та Apache Commons можуть все-таки запропонувати більшу гнучкість):
Collections.sort(reportList, Comparator.comparing(Report::getReportKey)
.thenComparing(Report::getStudentNumber)
.thenComparing(Report::getSchool));
Завдяки відповіді @ gaoagong нижче .
Зверніть увагу, що однією з переваг тут є те, що геттери оцінюються ліниво (наприклад, getSchool()
оцінюється лише за необхідності).
Брудний і заплутаний: сортування вручну
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);
Очевидно, що це більш стисло, але ще більше схильне до помилок, оскільки ви втрачаєте пряме посилання на поля, використовуючи замість них рядки (без типозахисту, автоматичного рефакторингу). Тепер, якщо поле перейменовано, компілятор навіть не повідомляє про проблему. Більше того, оскільки це рішення використовує відбиття, сортування відбувається набагато повільніше.
Як дістатися: сортування за допомогою 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();
}
});
Це набагато краще, але для найпоширенішого випадку використання потрібен певний код котла: нульові значення за замовчуванням повинні оцінюватися менше. Для нульових полів потрібно надати додаткову директиву Guava, що робити в такому випадку. Це гнучкий механізм, якщо ви хочете зробити щось конкретне, але часто вам потрібен регістр за замовчуванням (тобто. 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 ComparisonChain, цей клас бібліотеки легко сортує в декількох полях, але також визначає поведінку за замовчуванням для нульових значень (тобто. 1, a, b, z, null). Однак ви також не можете вказати нічого іншого, якщо ви не надаєте власний компаратор.
Знову ж таки, як зазначено у коментарях нижче, усі ці одержувачі оцінюються негайно для кожного порівняння.
Таким чином
Врешті-решт це зводиться до смаку та необхідності гнучкості (Guava's ComparisonChain) проти стислого коду (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 Collections вже використовує це:
ComparatorUtils.chainedComparator (comparatorCollection)
Collections.sort(list, ComparatorUtils.chainedComparator(comparators));