(ursprünglich von Möglichkeiten zum Sortieren von Objektlisten in Java anhand mehrerer Felder )
Originaler 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 .
Beachten Sie, dass ein Vorteil hierbei darin besteht, dass die Getter träge bewertet werden (z. B. getSchool()
wird nur bewertet, wenn dies relevant ist).
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 einzige Vorteil ist, dass Getter nur dann aufgerufen werden, wenn dies relevant ist.
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();
}
});
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 (z. B. 1, a, b, z, null).
Und wie in den Kommentaren unten angegeben, werden diese Getter alle sofort für jeden Vergleich bewertet.
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.
Wie in den Kommentaren unten angegeben, werden diese Getter alle sofort für jeden Vergleich bewertet.
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));