얼마 전 내가 작성한 코드에 당연히 있어야 할 null 체크가 빠져 있어 프로젝트 테스트 진행에 차질이 발생하였다. 리스트에 대한 for문 수행 전 null 체크가 누락된 것이 원인이었는데 다행히 원인이 발생하는 부분을 금방 찾아 조치하였으나, 개발한지 어느덧 3년차인 지금까지도 개발자라면 당연히 작성해야 할 NullPointerException에 대한 방어로직에 대한 습관이 갖추어져 있지 않은 것 같아 부끄러웠다...
반성하는 의미에서 기본 중의 기본이라 할 수 있는 조건문에서의 NullPointerException 회피에 대해 다시 한 번 정리한다.
class Logbook {
void writeMessage(String message, Path location) throws IOException {
if (Files.isDirectory(location)) {
throw new IllegalArgumentException("The path is invalid!");
}
if (message.trim().equals("") || message == null) {
throw new IllegalArgumentException("The message is invalid!");
}
String entry = LocalDate.now() + ": " + message;
Files.write(location, Collections.singletonList(entry),
StandardCharsets.UTF_8, StandardOpenOption.CREATE,
StandardOpenOption.APPEND);
}
}
위 코드는 location 인수로 명시한 파일 시스템 내 특정 파일에 로그 메시지를 정리하는 코드이다.
NullPointerException은 null을 참조하는 메서드를 호출하거나 속성에 접근할 때 발생하는데, 위 코드는 null에 대한 참조를 올바르게 확인하고 있지 않다.
null 참조를 확인할 때에는 반드시 순서를 올바르게 지켜야 하는데, 위 코드에서는 location이 null이면 Files.isDirectory()는 NullPointerException과 함께 실패한다. 다음 조건문에서도 message가 null이면 message.equals("")를 먼저 확인하므로 마찬가지로 NullPointerException이 발생한다.
class Logbook {
void writeMessage(String message, Path location) throws IOException {
if (message == null || message.trim().isEmpty()) {
throw new IllegalArgumentException("The message is invalid!");
}
if (location == null || Files.isDirectory(location)) {
throw new IllegalArgumentException("The path is invalid!");
}
String entry = LocalDate.now() + ": " + message;
Files.write(location, Collections.singletonList(entry),
StandardCharsets.UTF_8, StandardOpenOption.CREATE,
StandardOpenOption.APPEND);
}
}
위 코드는 아래와 같이 잘못된 코드의 이슈를 모두 해결하였다.