Posts 자바에서 null 처리에 대해 생각해보기
Post
Cancel

자바에서 null 처리에 대해 생각해보기

나는 언제 주로 null을 사용했을까 ?

  • 참조값이 ‘없음’을 표현하는 경우
  • 따라서, 보통 아래와 같이 코드를 작성하게 되는 것 같다.
1
2
3
if (obj != null) {
    // do something
}
1
2
3
4
5
if (obj == null) {
    // null인게 비정상적인 상황이라면 적절한 예외 발생시키기
}

// do something

그렇다면, null의 단점은 뭐가 있을까 ?

  • 해당 객체를 다룰 때 주의하지 않으면 NPE가 발생한다.
    • 따라서, null인지를 확인하는 코드가 반복적으로 나타나야하고 이로 인해 코드가 지저분해질 수 있다.
    • 또한, 이런 null 객체들이 코드 이곳 저곳에 돌아다니면 NPE가 발생할 확률은 높아질 것이고 이로 인해 서비스의 신뢰성이 낮아질 수 있다.
  • null을 리턴받는 입장에서는 이게 진짜 값이 없는 것인지, 어떤 에러가 발생한 것인지 등 해당 값만으로는 정확한 맥락을 파악할 수가 없거나, 상세 구현을 확인해봐야 한다.
    • 정확한 맥락을 파악할 수 없다는 것은, 그에 따른 적절한 처리를 하기가 어렵다는 것

그럼 어떤식으로 처리하면 좋을까 ?

null 리턴

  • private 메서드와 같이 사용 범위가 제한적인 경우

예외 발생

  • 참조값이 없는게 예외로 간주되어야하는 경우

Optional

  • 이펙티브 자바를 참고해보면, null인게 예외인지 아닌지 등을 호출한 쪽에서 맥락에 따라 판단해야하는 경우 Optional이 괜찮은 선택일 수 있음
    (CheckedException처럼 호출자에게 이 메서드를 호출할시 ‘리턴값이 없을 수 있음’을 명확하게 알릴 수 있기 때문에)

빈 컬렉션

  • new ArrayList<>();, Collections.emptyList();
    • NPE가 발생하지 않는다. 이에 따라, 코드가 조금 더 깔끔해질 수 있다.
1
2
3
4
5
List<Item> items = getItems();
// if (items != null && !items.isEmpty()) -> 이런 체크가 불필요
for (Item item : items) {
  ...
}

null 오브젝트 패턴

1
2
3
public interface Result {
  void doSomething();
}
1
2
3
4
5
6
public class RealResult implements Result {
  @Override
  public void doSomething() {
    System.out.println("Doing real work");
  }
}
1
2
3
4
5
6
public class NullResult implements Result {
  @Override
  public void doSomething() {
    // do nothing
  }
}
1
2
3
4
5
6
7
public Result findById(String id) {
  if (/* not found */) {
    return new NullResult();
  } else {
    return new RealResult();
  }
}
1
2
Result result = findById("someId");
result.doSomething(); // null 체크 없이 안전하게 호출
This post is licensed under CC BY 4.0 by the author.