(von Möglichkeiten zum Sortieren von Objektlisten in Java anhand mehrerer Felder )
Arbeitscode in diesem Kern
Verwenden von Java 8 Lambda (hinzugefügt am 10. April 2019)
Java 8 löst dies gut durch Lambda (obwohl Guava und Apache Commons möglicherweise noch mehr Flexibilität bieten):
Collections.sort(reportList, Comparator.comparing(Report::getReportKey)
.thenComparing(Report::getStudentNumber)
.thenComparing(Report::getSchool));
Vielen Dank an @ gaoagongs Antwort unten .
Chaotisch und verschlungen: Sortieren von Hand
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);
}
});
Dies erfordert viel Eingabe, Wartung und ist fehleranfällig.
Der reflektierende Weg: Sortieren mit BeanComparator
ComparatorChain chain = new ComparatorChain(Arrays.asList(
new BeanComparator("size"),
new BeanComparator("nrOfToppings"),
new BeanComparator("name")));
Collections.sort(pizzas, chain);
Dies ist natürlich prägnanter, aber noch fehleranfälliger, da Sie Ihren direkten Verweis auf die Felder verlieren, indem Sie stattdessen Strings verwenden (keine Typensicherheit, automatische Refactorings). Wenn nun ein Feld umbenannt wird, meldet der Compiler nicht einmal ein Problem. Da diese Lösung Reflexion verwendet, ist die Sortierung außerdem viel langsamer.
Anreise: Sortieren mit Google Guavas 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();
// 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();
*/
}
});
Dies ist viel besser, erfordert jedoch einen Kesselplattencode für den häufigsten Anwendungsfall: Nullwerte sollten standardmäßig weniger bewertet werden. Für Nullfelder müssen Sie Guava eine zusätzliche Anweisung geben, was in diesem Fall zu tun ist. Dies ist ein flexibler Mechanismus, wenn Sie etwas Bestimmtes tun möchten, aber häufig den Standardfall (dh 1, a, b, z, null).
Sortieren mit 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();
}
});
Wie Guavas ComparisonChain sortiert diese Bibliotheksklasse problemlos nach mehreren Feldern, definiert jedoch auch das Standardverhalten für Nullwerte (z. B. 1, a, b, z, null). Sie können jedoch auch nichts anderes angeben, es sei denn, Sie stellen Ihren eigenen Komparator bereit.
So
Letztendlich kommt es auf den Geschmack und das Bedürfnis nach Flexibilität (Guavas ComparisonChain) im Vergleich zu prägnantem Code (Apaches CompareToBuilder) an.
Bonusmethode
Ich fand eine schöne Lösung , dass mehrere Komparatoren in der Reihenfolge ihrer Priorität Mähdrescher auf Codereview in einem 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));
}
}
Natürlich hat Apache Commons Collections bereits einen Nutzen dafür:
ComparatorUtils.chainedComparator (compareatorCollection)
Collections.sort(list, ComparatorUtils.chainedComparator(comparators));