원문 : https://www.baeldung.com/java-8-sort-lambda
우선 아래와 같은 class가 있다고 했을때
public class Human {
private String name;
private int age;
public String getName() {
return name;
}
public int getAge() {
return age;
}
public Human(String name, int age) {
this.name = name;
this.age = age;
}
}
Java8 이전에는 아래 코드와 같이 Comparator를 구현하여 정렬에 사용했다.
void givenPreLambda_whenSortingEntitiesByName_thenCorrectlySorted() {
List<Human> humans = new ArrayList<>();
humans.add(new Human("Sarah", 10));
humans.add(new Human("Jack", 12));
Collections.sort(humans, new Comparator<Human>() {
@Override
public int compare(Human h1, Human h2) {
return h1.getName().compareTo(h2.getName());
}
});
assertThat(humans.get(0), equalTo(new Human("Jack", 12)));
}
이랬던 코드를 Java8에서 람다가 등장한 이후로 아래와 같이 작성이 가능해 졌다.
void whenSortingEntitiesByName_thenCorrectlySorted() {
List<Human> humans = new ArrayList<>();
humans.add(new Human("Sarah", 10));
humans.add(new Human("Jack", 12));
// humans.sort((Human h1, Human h2) -> h1.getName().compareTo(h2.getName()));
humans.sort((h1, h2) -> h1.getName().compareTo(h2.getName()));
assertThat(humans.get(0), equalTo(new Human("Jack", 12)));
}
위 코드는 다시 Comparator에서 static 으로 제공하는 comparing() 함수와 메소드 참조를 이용해서 아래와 같이 작성할 수 있다. comparing() 함수의 파라미터는 Comparable 의 구현체 이어야 한다.
void givenInstanceMethod_whenSortingEntitiesByName_thenCorrectlySorted() {
List<Human> humans = Arrays.asList(
new Human("Sarah", 10),
new Human("Jack", 12)
);
// Collections.sort(humans, Comparator.comparing(Human::getName));
humans.sort(Comparator.comparing(Human::getName));
assertThat(humans.get(0), equalTo(new Human("Jack", 12)));
}
만약 정렬 순서를 변경하고 싶다면, Comparator에 reversed() 함수를 이용한다.
humans.sort(Comparator.comparing(Human::getName).reversed());
이름순, 나이순 정렬 처럼 두개 이상의 정렬 인자를 적용하고 싶다면 아래처럼 thenComparing() 함수를 이용한다.
humans.sort(
Comparator.comparing(Human::getName).thenComparing(Human::getAge)
);
이상의 방법은 collection 의 sort함수를 이용하기때문에 sort를 수행하고 나면 원래 collection 의 순서가 변경된다.
이를 방지하고 싶다면 stream 을 이용해서 정렬을 수행하고 원본 collection 과 별도의 정렬된 collection 을 생성하면 된다.
우선 Comparable을 구현한 타입이라면 아래 처럼 stream().sorted() 함수를 이용하면된다.
void givenStreamNaturalOrdering_whenSortingEntitiesByName_thenCorrectlySorted() {
List<String> letters = Arrays.asList("B", "A", "C");
List<String> sortedLetters = letters.stream().sorted().collect(Collectors.toList());
assertThat(sortedLetters.get(0), equalTo("A"));
}
Comparator.comparing() 함수를 사용할 수도 있다.
void givenStreamComparatorOrdering_whenSortingEntitiesByName_thenCorrectlySorted() {
List<Human> humans = Arrays.asList(new Human("Sarah", 10), new Human("Jack", 12));
List<Human> sortedHumans = humans.stream()
.sorted(Comparator.comparing(Human::getName))
.collect(Collectors.toList());
assertThat(sortedHumans.get(0), equalTo(new Human("Jack", 12)));
assertThat(humans.get(0), equalTo(new Human("Sarah", 10)));
}
Comparator을 사용하기 때문에 위에서 봤었던, reversed()함수나 thenComparing() 함수도 사용 할 수 있다.
Collection 에 null 값이 포함되는 경우 Comparator.nullsFirst(), Comparator.nullsLast() 함수를 이용해서 null 값을 colleciton 맨 앞이나 뒤로 오게 설정 할 수도 있다.
void givenANullElement_whenSortingEntitiesByName_thenMovesTheNullToLast() {
List<Human> humans = Arrays.asList(null, new Human("Jack", 12), null);
humans.sort(Comparator.nullsLast(Comparator.comparing(Human::getName)));
assertNotNull(humans.get(0));
assertNull(humans.get(1));
assertNull(humans.get(2));
}
void givenANullElement_whenSortingEntitiesByName_thenMovesTheNullToStart() {
List<Human> humans = Arrays.asList(null, new Human("Jack", 12), null);
humans.sort(Comparator.nullsFirst(Comparator.comparing(Human::getName)));
assertNull(humans.get(0));
assertNull(humans.get(1));
assertNotNull(humans.get(2));
}
'Java' 카테고리의 다른 글
Java Optional 사용법 (0) | 2023.09.03 |
---|---|
Java 람다(Lambda) 표현식, Functional Interface 에 대한 조언 (0) | 2023.08.26 |
CompletableFuture 사용법 (0) | 2020.02.07 |
apache HttpClient, javax.net.ssl.SSLHandshakeException 발생시 대처법 (0) | 2019.12.30 |
for each 문에 대하여 (0) | 2014.03.04 |