널 반환하지 않기

A Kind Dev·2022년 6월 15일
0

자바 코딩의 기술

목록 보기
2/7
post-thumbnail

얼마 전 null을 리턴하는 API를 호출하여 사용하다 에러가 발생한 적이 있다. 반환값을 확인하지 않은 나도 잘못이지만, 예고없이 null을 리턴하는 API를 개발한 담당자도 살짝 원망스러웠는데 책을 보는 도중 마침 관련된 내용이 있어 정리한다.

결론은, 메서드의 리턴값은 가급적 null을 리턴해서는 안된다는 것!


잘못된 코드

class SpaceNations {

    static List<SpaceNation> nations = Arrays.asList(
            new SpaceNation("US", "United States"),
            new SpaceNation("RU", "Russia")
    );

    static SpaceNation getByCode(String code) {
        for (SpaceNation nation : nations) {
            if (nation.getCode().equals(code)) {
                return nation;
            }
        }
        return null;
    }
}

class SpaceNation {

    final String code;
    final String name;

    SpaceNation(String code, String name) {
        this.code = code;
        this.name = name;
    }

    String getName() {
        return name;
    }

    String getCode() {
        return code;
    }
}

class Usage {

    static void main(String[] args) {
        String us = SpaceNations.getByCode("US").getName();
        // -> "United States"
        String anguilla = SpaceNations.getByCode("AI").getName();
        // -> NullPointerException
    }
}

위 코드는 String을 메서드로 전달하면 대응하는 SpaceNation 인스턴스가 반환되고 알려지지 않은 국가코드면 null이 반환된다.

메서드 호출 시 적절히 반환할 값이 없으면 그냥 null을 반환하는 프로그램이 있다. 이렇게 되면 프로그램의 안정성에 크게 위협이 되는데, 메서드가 null을 반환할 가능성이 있으니 매번 명시적으로 반환값을 확인해야 하고 그렇지 않으면 NullPointerException이 발생할 위험이 있기 때문이다.
null 체크는 습관적으로 진행되어야 하지만 누군가는 잊어버리고 예외는 일어나기 마련이다.

null이 부적절하다면 그 대신 무엇을 반환해야 할까?


올바른 코드

class SpaceNations {

    /** Null object. */
    static final SpaceNation UNKNOWN_NATION = new SpaceNation("", "");

    static List<SpaceNation> nations = Arrays.asList(
            new SpaceNation("US", "United States"),
            new SpaceNation("RU", "Russia")
    );

    static SpaceNation getByCode(String code) {
        for (SpaceNation nation : nations) {
            if (nation.getCode().equals(code)) {
                return nation;
            }
        }
        return UNKNOWN_NATION;
    }
}

class SpaceNation {
    final String code;
    final String name;

    SpaceNation(String code, String name) {
        this.code = code;
        this.name = name;
    }

    String getCode() {
        return code;
    }

    String getName() {
        return name;
    }
}

class Usage {

    static void main(String[] args) {
        String us = SpaceNations.getByCode("US").getName(); // -> "United States"
        String anguilla = SpaceNations.getByCode("AI").getName(); // -> ""
    }
}

위 코드는 아래와 같은 방법으로 잘못된 코드의 이슈를 해결하였다.

SpaceNations.getByCode 메서드에서 static 변수로 UNKNOWN_NATION 을 선언하여 빈 SpaceNation 객체를 생성해두고, null 대신 리턴한다.


결론

null을 반환하는 대신 아래와 같이 처리할 수 있다.

  1. IllegalArgumentException이나 NoSuchElementException과 같은 예외를 던지는 방법이 있다.
    (그런데 나는 개인적으로 선호하지 않는 방법이다. 시스템 안정성과 개발 생산성을 향상시키기 위해서는 공통 개발자가 아닌 일반 개발자는 가급적 소스에서 try-catch 할 일을 줄여야 한다고 생각하기 때문에...)

  2. 널 객체(null object)를 반환할 수 있다.
    위 예제에서 사용한 방법으로, 빈 문자열, 빈 컬렉션, 또는 빈 클래스 인스턴스 등으로 객체에 실질적 값이 없을을 명시적으로 표현하여 방식이다.
    이 경우 어떻게 대응할지는 여전히 호출하는 쪽에 달려 있지만, 값을 무시하든 예외를 던지든 선택의 여지는 생긴다.


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

profile
친절한 개발자

0개의 댓글