조건문에서 NullPointerException 피하기

A Kind Dev·2022년 6월 15일
0

자바 코딩의 기술

목록 보기
1/7
post-thumbnail

얼마 전 내가 작성한 코드에 당연히 있어야 할 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);
    }
}

위 코드는 아래와 같이 잘못된 코드의 이슈를 모두 해결하였다.

  1. 모든 인수에 대해 null값 여부를 확인한다.
  2. 메서드 파라미터의 순서에 따라 null 체크를 수행한다. 매개변수 유효성 검사를 적절한 순서로 수행하면 읽기 흐름이 크게 향상되며, 파라미터에 대한 null 체크를 빠뜨릴 위험도 적다.
  3. 내장 메서드를 사용해 빈 문자열인지 여부를 확인한다.

결론

  1. 인수를 검증할 때에는 순서가 중요하다. 반드시 null을 먼저 확인한 후 도메인에 따라 유효하지 않은 값을 검사한다.
  2. 빈 문자열이나 빈 리스트처럼 일반적인 기본값을 먼저 검사한 후 특정 값을 확인한다.
  3. 메서드 인수로 null을 전달하는 방식은 메서드가 파라미터 없이도 올바르게 기능한다는 뜻이니 가급적 피한다. 꼭 해야 한다면 매개변수가 있는 메서드와 없는 메서드 두 개로 리팩터링한다.

출처 : [자바 코딩의 기술], 사이먼 하러 외 3인, 길벗 출판사

profile
친절한 개발자

0개의 댓글