.sorted(Comparator.comparing(Member::getAge)) // member의 age 속성을 기준으로 정렬한다.
.collect(toList());
System.out.println(sortedMemberList);
결과
1
[Member(age=5), Member(age=10), Member(age=20)]
위와 같이 Comparator 클래스에서 제공하는 comparing 메서드를 사용하면 원하는 정렬 기준을 람다식으로 표현하여 정렬을 쉽게 할 수 있다. (물론 정렬 기준이 되는 속성은 Comparable 타입이어야 한다. 여기서 Member의 age는 Integer이다.)
Comparator.comparing() 메서드는 두 번째 인자를 받을 수 있는 메서드가 하나 더 오버로드 되어있는데, 두 번째 인자는 정렬의 순서를 결정하는 Comparator를 받는다. 만약 Member를 나이를 기준으로 정렬하되 역순으로 정렬하고 싶으면 다음과 같이 작성한다.
at java.util.Comparator.lambda$comparing$77a9974f$1(Comparator.java:469)
at java.util.TimSort.countRunAndMakeAscending(TimSort.java:355)
at java.util.TimSort.sort(TimSort.java:220)
at java.util.Arrays.sort(Arrays.java:1512)
...
결과는 예상 했던대로 NullPointerException이 발생하게 된다. compareTo()를 호출할 대상 Integer(age)가 null이기 때문이다. 물론 처음부터 null이 설정될 수 없게 해놓으면 좋겠지만 실무를 하다보면 그렇지 않은 경우를 많이 만나게 된다. 뭐 어찌됐던 개발자는 일방통행 도로라고 해도 양쪽을 모두 살피고 길을 건너야 하지 않겠는가.
자바는 이런 경우에 사용할 수 있는 2가지 Comparator를 제공한다. 바로 Comparator.nullsFirst()와 Comparator.nullsLast()이다.
Comparator.nullsFirst(), Comparator.nullsLast()
위 두개의 Comparator를 사용하면 정렬 기준 값이 null이어도 NPE가 발생하지 않고 안전하게 정렬을 할 수 있다. 두 객체의 차이는 이름에서도 알 수 있듯이 null을 가진 객체를 앞으로 보내느냐 뒤로 보내느냐의 차이이다. 아래 코드처럼 사용할 수 있다.
Comparator.comparing() 메서드의 두 번째 인자를 넘길 때 Compartor.nullsLast()로 한 번 감싸서 넘겨주게 되면, null을 갖는 객체들은 전부 뒤쪽으로 정렬이 되고 나머지는 주어진 정렬 순서에 맞게 정렬이 된다. 만약 null을 앞으로 정렬하고 나머지는 나이의 역순으로 정렬하고 싶다면 아래와 같이 하면 된다.