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 |
댓글