프로그래밍 노트/Effective 시리즈

null이 아닌, 빈 컬렉션이나 배열을 반환해야 한다.

깡냉쓰 2020. 1. 7. 22:59
728x90
반응형
private final List<Cheese> cheesesInStock = ...;

/**
 * @return 매장 안의 모든 치즈 목록을 반환한다.
 *       단, 재고가 하나도 없다면 null을 반환한다.
 */
public List<Cheese> getCheese(){
        return cheesesInStock.isEmpty() ? null : new ArrayList<>(cheesesInStock);
}

위의 코드의 문제점은 null을 반환한다는 것이다. 재고가 없다고 해서 특별히 취급할 이유는 없는대도 말이다..
만약에 재고가 없을 경우 null을 반환하는 것을 고집한다면, 이 메소드를 사용하는 모든 클라이언트는 아래와 같은 방어 코드를 넣어줘야 한다.

List<Cheese> cheeses = shop.getCheese();
if(cheeses != null && cheeses.contains(Cheese.STILTON)) ...

방어코드를 빼먹으면 오류가 발생할 수 있을뿐만 아니라, null을 반환하는 쪽에서도 이 상황을 특별히 취급해줘야 하므로 코드가 더 복잡해질 수 있다.

때로는 빈 컨테이너를 할당하는데 비용이 드니 null을 반환하는 쪽이 낫다는 주장이 있는데, 이 주장은 틀린 주장이다.

  1. 이 할당이 성능 저하의 주범이라고 확인되지 않는 한, 이 정도의 성능 차이는 신경 쓸 수준이 못 된다.
  2. 빈 컬렉션과 배열은 굳이 새로 할당하지 않고도 반환할 수 있다.

위의 두가지 이유때문이다.

매번 똑같은 빈 불변 컬렉션을 반환하여 빈 컬렉션 할당에 최적화를 시켜줄 수 있다.
알다시피 불변 객체는 자유롭게 공유해도 안전하다.
Collections.emptyList(), Collections.emptySet(), Collections.emptyMap()을 사용하자.

public List<Cheese> getCheese(){
        return cheesesInStock.isEmpty() ? Collections.emptyList() : new ArrayList<>(cheesesInStock);
}

배열도 마찬가지이다. 절대 null을 반환하지 말고 길이가 0인 배열을 반환하자.

private static final Cheeses[] EMPTY_CHEESE_ARRAY = new Cheese[0];

public Cheeses[] getCheeses(){
        return cheesesInStock.toArray(EMPTY_CHEESE_ARRAY);
}

결론

null이 아닌, 빈 배열이나 컬렉션을 반환하라. null을 반환하는 API는 사용하기 어렵고 오류 처리 코드도 늘어난다. 그렇다고 성능이 좋은 것도 아니다.

728x90
반응형