(da Ways per ordinare gli elenchi di oggetti in Java in base a più campi )
Codice di lavoro in questo senso
Utilizzo di Java 8 lambda (aggiunto il 10 aprile 2019)
Java 8 risolve questo problema con Lambda (anche se Guava e Apache Commons potrebbero offrire ancora maggiore flessibilità):
Collections.sort(reportList, Comparator.comparing(Report::getReportKey)
.thenComparing(Report::getStudentNumber)
.thenComparing(Report::getSchool));
Grazie alla risposta di @ gaoagong di seguito .
Disordinato e contorto: ordinamento a mano
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);
}
});
Ciò richiede molta digitazione, manutenzione ed è soggetto a errori.
Il modo riflessivo: ordinare con BeanComparator
ComparatorChain chain = new ComparatorChain(Arrays.asList(
new BeanComparator("size"),
new BeanComparator("nrOfToppings"),
new BeanComparator("name")));
Collections.sort(pizzas, chain);
Ovviamente questo è più conciso, ma ancora più soggetto a errori man mano che perdi il tuo riferimento diretto ai campi usando invece Stringhe (nessuna sicurezza tipografica, auto-refactoring). Ora se un campo viene rinominato, il compilatore non segnalerà nemmeno un problema. Inoltre, poiché questa soluzione utilizza la riflessione, l'ordinamento è molto più lento.
Come arrivarci: ordinamento con ComparisonChain di 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();
*/
}
});
Questo è molto meglio, ma richiede un codice di targa della caldaia per il caso d'uso più comune: i valori null dovrebbero essere valutati meno per impostazione predefinita. Per i campi null, devi fornire una direttiva aggiuntiva a Guava che cosa fare in quel caso. Questo è un meccanismo flessibile se vuoi fare qualcosa di specifico, ma spesso vuoi il caso predefinito (es. 1, a, b, z, null).
Ordinamento con 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();
}
});
Come Guison's ComparisonChain, questa classe di libreria ordina facilmente su più campi, ma definisce anche il comportamento predefinito per i valori null (es. 1, a, b, z, null). Tuttavia, non è possibile specificare nient'altro, a meno che non si fornisca il proprio comparatore.
così
Alla fine si riduce al sapore e alla necessità di flessibilità (Guava's ComparisonChain) rispetto al codice conciso (Apache's CompareToBuilder).
Metodo bonus
Ho trovato una bella soluzione che combina più comparatori in ordine di priorità su CodeReview in un 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));
}
}
Ofcourse Apache Commons Collections ha già un util per questo:
ComparatorUtils.chainedComparator (comparatorCollection)
Collections.sort(list, ComparatorUtils.chainedComparator(comparators));