(원래 여러 필드를 기반으로 Java에서 객체 목록을 정렬 하는 방법에서 )
이 요점의 원래 작업 코드
Java 8 람다 사용 (2019 년 4 월 10 일 추가됨)
Java 8은 Lambda로이 문제를 훌륭하게 해결합니다 (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);
}
});
이것은 많은 타이핑, 유지 보수가 필요하며 오류가 발생하기 쉽습니다. 유일한 장점은 getter 가 관련이있을 때만 호출 .
반사적 방식 : BeanComparator로 정렬
ComparatorChain chain = new ComparatorChain(Arrays.asList(
new BeanComparator("size"),
new BeanComparator("nrOfToppings"),
new BeanComparator("name")));
Collections.sort(pizzas, chain);
분명히 이것은 더 간결하지만 대신 문자열을 사용하여 필드에 대한 직접 참조를 잃어 버리기 때문에 오류가 발생하기 쉽습니다 (유형 안전성, 자동 리팩토링 없음). 이제 필드의 이름이 변경되면 컴파일러는 문제를보고하지도 않습니다. 또한이 솔루션은 리플렉션을 사용하기 때문에 정렬이 훨씬 느립니다.
찾아 가기 : Google Guava의 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();
}
});
이것은 훨씬 더 좋지만 가장 일반적인 사용 사례에 대해 약간의 상용구 코드가 필요합니다. null 값은 기본적으로 더 작은 값이어야합니다. 널 필드의 경우 Guava에이 경우 수행 할 작업에 대한 추가 지시문을 제공해야합니다. 특정 작업을 수행하려는 경우 유연한 메커니즘이지만 종종 기본 케이스 (예 : 1, a, b, z, null)를 원합니다.
그리고 아래 주석에서 언급했듯이 이러한 getter는 각 비교에 대해 모두 즉시 평가됩니다.
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의 ComparisonChain과 마찬가지로이 라이브러리 클래스는 여러 필드에서 쉽게 정렬되지만 null 값 (예 : 1, a, b, z, null)에 대한 기본 동작도 정의합니다. 그러나 자신의 Comparator를 제공하지 않는 한 다른 것도 지정할 수 없습니다.
다시 말하지만, 아래 주석에서 언급했듯이 이러한 getter는 각 비교에 대해 모두 즉시 평가됩니다.
그러므로
궁극적으로 그것은 풍미와 유연성 (Guava의 ComparisonChain) 대 간결한 코드 (Apache의 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));
}
}
Ofcourse Apache Commons Collections에는 이미 다음과 같은 유틸리티가 있습니다.
ComparatorUtils.chainedComparator (comparatorCollection)
Collections.sort(list, ComparatorUtils.chainedComparator(comparators));