Java stream sort multiple fields
stream을 사용하는 도중 자주 사용하지만 자꾸 까먹어 다시 찾아보는 기능을 기록하려합니다.
우리는 객체를 사용하면서 정렬을 하거나, 정렬을 하고 출력을 하는등에 대한 기능을 사용할 때가 많습니다.
이 기능은 스트림을 사용하면 간단하게 사용할 수 있습니다. 다음은 예제 코드입니다.
// Integer List를 reverseOrder한 결과
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(45);
list.add(6);
list.add(3);
list.add(7);
list.add(11);
list.add(13);
list.add(1);
list.stream().sorted(Comparator.reverseOrder()).forEach(s -> System.out.println(s));
}
// 결과 값
45
13
11
7
6
3
2
1
1
하지만 보통 우리는 list에 직접 만든 도메인을 추가하고 해당값을 이용하여 sort를 진행합니다.
그럼 아래는 class하나를 선언했다 가정하고 sort하는 코드를 작성하겠습니다.
// multi key에 대한 sort.
public static void main(String[] args) {
List<Product> sss = new ArrayList<>();
sss.add(new Product(3, 6));
sss.add(new Product(3, 5));
sss.add(new Product(5, 7));
sss.add(new Product(5, 10));
sss = sss.stream().sorted(Comparator.comparing(Product::getCost, Comparator.reverseOrder()).thenComparing(Product::getCnt)).collect(Collectors.toList());
for(Product t : sss) {
System.out.println(t.cost+" "+ t.cnt);
}
}
class Product{
int cost;
int cnt;
public Product(int cost, int cnt) {
this.cost = cost;
this.cnt = cnt;
}
public int getCost() {
return cost;
}
public void setCost(int cost) {
this.cost = cost;
}
public int getCnt() {
return cnt;
}
public void setCnt(int cnt) {
this.cnt = cnt;
}
}
// 결과 값
5 7
5 10
3 5
3 6
이번 예제의 경우 stream 안에서 forEach를 하지않고 list를 반환하도록 설정했습니다.
해당 결과의 경우, cost의 경우 Comparator.reverseOrder() 를 통하여 cost는 내림차순, cnt는 오름차순을 통해 정렬된 결과를 나타내게 됩니다. ( Comparator.reverseOrder()을 사용하지 않는 경우 기본 오름차순입니다. )
또한 마지막 .collect() 부분을 통하여 list를 반환하게 됩니다.
하지만 여기서.. 비교해야할 field가 많거나, String 내부 단어에 의해 커스텀한 정렬이 필요한경우.
implements Comparable<Class> 구현을 통하여 해당부분 sort가 가능합니다.
// stream으로 sort받는 부분만 변경
sss = sss.stream().sorted().collect(Collectors.toList());
class Product implements Comparable<Product> {
// 위와 동일한 getter, setter, constructor
@Override
public int compareTo(Product o) {
if(this.cost > o.cost)
return -1;
return 1;
}
}
// 결과 값
5 7
5 10
3 6
3 5
해당 Comparable 구현을 통해서도 sort시 기준을 적용할 수 있게됩니다.
비교적 Domain에 별다른 implement를 좋아하진 않으나, 복잡하며 반드시 코드상에서 sort가 필요하다면 써야할지도 몰르겠습니다.