이펙티브 자바를 읽다가 null
에 대한 체크를 위해 Objects
클래스의 requireNonNull
을 사용하는 것을 알게 되었다. 따라서, 이에 대해 정리하고 왜 사용하는지에 대해 알아보자.
requireNonNull
requireNonNull
은
Java 7에 추가된
Objects
클래스에서 제공하는 Null 체크를 위한 메서드
이다.
파라미터로 입력된 값이 null이라면 NullPointerException(NPE)이 발생하고, 그렇지 않다면 입력값을 그래도 반환한다.
Java 11을 기준으로 requireNonNull 은 다음과 같이 3가지로 오버로딩 되어있다.
리턴 타입(Return Type) | 메서드(Method) |
T | requireNonNull(T obj) |
T | requireNonNull(T obj, String message) |
T | requireNonNull(T obj, Supplier messageSupplier) |
requireNonNull(T obj)
첫 번째 메서드는 null
을 전달하면 오류메시지가 비어있는 NPE를 던진다.
Objects.requireNonNull(null);
// 결과 : java.lang.NullPointerException
String normalStr = Objects.requireNonNull("일반적인 객체");
System.out.println(normalStr);
// 결과 : 일반적인 객체
requireNonNull(T obj, String message)
두 번째 메서드는 null
을 전달하면, 두 번째 파라미터로 전달된 문자열을 오류메시지로 갖는 NPE를 던진다.
Objects.requireNonNull(null, "null은 입력될 수 없습니다.");
// 결과 : java.lang.NullPointerException: null은 입력될 수 없습니다.
requireNonNull(T obj, Supplier messageSupplier)
마지막 메서드는 null
을 전달하면, 두 번째 파라미터로 전달한 Supplier를 구현한 익명 함수의 반환값을 오류메시지로 갖는 NPE를 던진다.
Objects.requireNonNull(null, () -> "null은 입력될 수 없습니다.");
// 결과 : java.lang.NullPointerException: null은 입력될 수 없습니다.
실제 구현된 코드를 확인해보면, 위와 같다.
❓사용하는 이유
위 코드의 내용을 보면 너무 당연한 내용이다. null이면 NPE를 던지고, 아니라면 그대로 반환하기 때문이다. 그렇다면 requireNonNull
을 왜 사용할까?
Fail-Fast
첫 번째 이유로 Fail-Fast를 들 수 있다. Fail-Fast
란, 장애가 발생한 시점에서 즉시 파악할 수 있는 것을 말한다. 디버깅을 쉽게 하기 위해서 문제가 발생한 경우 즉각적으로 감지할 필요가 있다. 문제의 원인과 발생 지점이 멀리 떨어져 있다면, 오류를 찾는데 걸리는 시간이 오래 걸릴 것이다. 즉, 시스템이 복잡해 질 수록 장애를 발견하기 어렵게 된다.
명시성
다음 두 가지 예시 코드를 보자.
수동 null 체크
String nullString = null;
if(nullString == null) {
throw new NullPointerException("입력값이 null입니다.");
}
requireNonNull을 이용한 null 체크
String nullString = null;
Objects.requireNonNull(nullString, "입력값이 null입니다.");
위 두 코드를 확인해보면, requireNonNull
을 사용한 코드가 훨씬 가독성이 좋고, 명시적인 표현 방법인 것을 알 수 있다.