Free Lines Arrow
본문 바로가기
Language/Java

[Java] sort, nullsLast, nullsFirst

by skahn1215 2024. 3. 17.
728x90
반응형

Null safe 하게 정렬하기 

  • 컬렉션에서 정렬을 사용할때 값이 null로 들어 올수 있다면 다음함수를 꼭 써줘야 한다.
    그렇지 않으면 NullPointerException 이 발생한다 
    - nullsLast
    - nullsFirst

 

예제

  • orgin 필드를 보면 final 이 아니다
  • 즉 이 값은 널이 올수도 있다는 뜻이다. 
@Getter
public class Apple {
    private final Integer weight;
    private final Color color;
    private String origin;

    public Apple(int weight, Color color) {
        this.weight = weight;
        this.color = color;
    }
}

 

 

Comparing 사용

  • 아래 코드를 수행하면 nullpoint exception 이 발생한다.
  • 원인은 정렬 할때 origin으로 비교를 하는데 apple3 에는 origin 이 없기 때문이다.
  • AssertionsThrows 로 에러를 체크 할 수 있지만 실제 익셉션 로그를 보기 위해 처리를 하진 않았다.
    public List<Apple> orderNullPointException(List<Apple> apples) {
        apples.sort(java.util.Comparator.comparing(Apple::getOrigin));
        return apples;
    }
    
    
    @Test
    void occurNullPointException() {
        Apple apple1 = new Apple(1, Color.RED);
        apple1.updateOrigin("A");

        Apple apple2 = new Apple(2, Color.RED);
        apple2.updateOrigin("B");

        Apple apple3 = new Apple(2, Color.RED);

        List<Apple> apples = new ArrayList<>();
        apples.add(apple1);
        apples.add(apple2);
        apples.add(apple3);

        List<Apple> sortedApples = Comparator.orderNullPointException(apples);
    }

 

 

결과

java.lang.NullPointerException: Cannot invoke "java.lang.Comparable.compareTo(Object)" because the return value of "java.util.function.Function.apply(Object)" is null
	at java.base/java.util.Comparator.lambda$comparing$77a9974f$1(Comparator.java:473)

 

 

NullPointerException 이 발생하는 이유

  • comparing 함수를 들어 가보면  requireNonNull 을 체크하는 부분이 있다. 
  • requireNonNull 을 다시 타고 들어 가면 obj 가 null 일때 throw new NullPointerException 을 던지기 때문이다.
    public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
            Function<? super T, ? extends U> keyExtractor)
    {
        Objects.requireNonNull(keyExtractor);
        return (Comparator<T> & Serializable)
            (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
    }
    
    
        @ForceInline
    public static <T> T requireNonNull(T obj) {
        if (obj == null)
            throw new NullPointerException();
        return obj;
    }

 

 

어떻게 코드를 짜면 될까?

아래 두개를 사용해 주자

  • nullsLast
    - 정렬을 하되 null 값은 마지막으로 보낸다.
  • nullsFirst
    - 정렬을 하되 null 값을 첫번째로 정렬한다.

 

nullsLast

  • java.util.Comparator.nullsLast 를 추가해 null safe 하게 정렬을 해주었다.
  • null 값이 있다면 해당 값은 맨 뒤로 보낸다.
    public static List<Apple> orderNullLast(List<Apple> apples) {
        apples.sort(java.util.Comparator.comparing(Apple::getOrigin,
                java.util.Comparator.nullsLast(java.util.Comparator.naturalOrder())));
        return apples;
    }

 

결과

  • success 가 뜬다.
    @Test
    void orderNullLast() {
        Apple apple1 = new Apple(1, Color.RED);
        apple1.updateOrigin("A");

        Apple apple2 = new Apple(2, Color.RED);
        apple2.updateOrigin("B");

        Apple apple3 = new Apple(2, Color.RED);

        List<Apple> apples = new ArrayList<>();
        apples.add(apple1);
        apples.add(apple2);
        apples.add(apple3);

        List<Apple> sortedApples = Comparator.orderNullLast(apples);
        assertThat(sortedApples.get(0).getOrigin()).isEqualTo("A");
        assertThat(sortedApples.get(1).getOrigin()).isEqualTo("B");
        assertThat(sortedApples.get(2).getOrigin()).isNull();
    }

 

 

nullsFirst

  • java.util.Comparator.nullsFirst 를 추가해 null safe 하게 정렬을 해주었다.
  • null 값이 있다면 해당 값은 맨 앞으로 보낸다.
    public static List<Apple> orderNullFirst(List<Apple> apples) {
        apples.sort(java.util.Comparator.comparing(Apple::getOrigin,
                java.util.Comparator.nullsFirst(java.util.Comparator.naturalOrder())));
        return apples;
    }

 

결과

  • success 가 뜬다.
    @Test
    void orderNullFirst() {
        Apple apple1 = new Apple(1, Color.RED);
        apple1.updateOrigin("A");

        Apple apple2 = new Apple(2, Color.RED);
        apple2.updateOrigin("B");

        Apple apple3 = new Apple(2, Color.RED);

        List<Apple> apples = new ArrayList<>();
        apples.add(apple1);
        apples.add(apple2);
        apples.add(apple3);

        List<Apple> sortedApples = Comparator.orderNullFirst(apples);
        assertThat(sortedApples.get(0).getOrigin()).isNull();
        assertThat(sortedApples.get(1).getOrigin()).isEqualTo("A");
        assertThat(sortedApples.get(2).getOrigin()).isEqualTo("B");
    }

 

 

결론

  • 정렬를 할 값에 null 이 들어올수 있다면 nullsLast 또는 nullsFirst 를 써주자 
728x90
반응형

'Language > Java' 카테고리의 다른 글

[Java] Optional 제대로 쓰기  (0) 2023.02.06
[Java] Optional<T> 기본  (0) 2023.02.06
[Java] SQL Mapper 만들기  (0) 2022.10.20
[Java] Generic 메서드  (0) 2022.06.25
[Java] Generic 와일드 카드  (0) 2022.06.25

댓글