(de maneiras de classificar listas de objetos em Java com base em vários campos )
Código de trabalho nesta essência
Usando Java 8 lambda's (adicionado em 10 de abril de 2019)
O Java 8 resolve isso muito bem com o lambda (embora Guava e Apache Commons ainda possam oferecer mais flexibilidade):
Collections.sort(reportList, Comparator.comparing(Report::getReportKey)
.thenComparing(Report::getStudentNumber)
.thenComparing(Report::getSchool));
Graças à resposta de @ gaoagong abaixo .
Confuso e complicado: Classificação manual
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);
}
});
Isso requer muita digitação, manutenção e é propenso a erros.
A maneira reflexiva: Classificando com BeanComparator
ComparatorChain chain = new ComparatorChain(Arrays.asList(
new BeanComparator("size"),
new BeanComparator("nrOfToppings"),
new BeanComparator("name")));
Collections.sort(pizzas, chain);
Obviamente, isso é mais conciso, mas ainda mais suscetível a erros, pois você perde sua referência direta aos campos usando Strings (sem segurança tipográfica, auto-refatorações). Agora, se um campo for renomeado, o compilador nem relatará um problema. Além disso, como essa solução usa reflexão, a classificação é muito mais lenta.
Como chegar: Classificando com o ComparisonChain do 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();
*/
}
});
Isso é muito melhor, mas requer algum código da placa da caldeira para o caso de uso mais comum: valores nulos devem ter menos valor por padrão. Para campos nulos, você deve fornecer ao Guava uma diretiva extra o que fazer nesse caso. Esse é um mecanismo flexível se você deseja fazer algo específico, mas geralmente deseja o caso padrão (por exemplo, 1, a, b, z, null).
Classificação com o 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();
}
});
Como o ComparisonChain do Guava, essa classe de biblioteca classifica facilmente em vários campos, mas também define o comportamento padrão para valores nulos (ou seja, 1, a, b, z, null). No entanto, você também não pode especificar mais nada, a menos que você forneça seu próprio Comparador.
portanto
Em última análise, tudo se resume ao sabor e à necessidade de flexibilidade (ComparavaChain da Guava) versus código conciso (CompareToBuilder do Apache).
Método bônus
Encontrei uma boa solução que combina vários comparadores em ordem de prioridade no CodeReview em 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));
}
}
Claro que o Apache Commons Collections já tem um utilitário para isso:
ComparatorUtils.chainedComparator (comparatorCollection)
Collections.sort(list, ComparatorUtils.chainedComparator(comparators));