54. null이 아닌, 빈 컬렉션이나 배열을 반환하라

다음은 흔히 볼 수 있는 메서드다.

private final List<Cheese> chessesInStock = ...;

public List<Cheese> getCheeses(){
	return cheesesInStock.isEmpty() ? null
    		: new ArrayList<>(cheesesInStock);
}

사실, 재고가 없다고 해서 특별하게 취급할 필요는 없다. null 을 반환하기 위해서는 반환하는 쪽에서도 null 을 반환하는 상황을 특별하게 관리해줘야 하기 때문에 코드가 더 복잡해진다.

빈 컨테이너를 할당하는데 비용이 들기 때문에 null 이 낫다는 주장이 있지만 다음 두 가지 측면에서 틀린 주장이다.

  • 성능 분석 결과 빈 컨테이너 할당이 성능 저하의 주범이라고 확인되지 않는 한 이 정도의 성능 차이는 신경 쓸 수준이 아니다.
  • 빈 컬렉션과 배열은 굳이 새로 할당하지 않아도 반환할 수 있다.

빈 컬렉션을 반환하는 올바른 예

public List<Cheese> getCheeses(){
	return new ArrayList<>(cheesesInStock);
}

가능성은 적지만 사용 패턴에 따라서 빈 컬렉션을 할당하는게 성능을 눈에 띄게 떨어뜨릴 수도 있다. 다행히 해법은 간단하다. 매번 똑같은 빈 불변 컬렉션을 반환하는 것이다. 알다시피 불변 객체는 자유롭게 공유해도 안전하다. [아이템17] Collections.emptyList, Collections.emptyMap 이 그러한 예시다.

최적화 - 빈 컬렉션을 매번 새로 할당하지 않아도 된다.

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

배열을 사용할 때도 마찬가지다. 절대로 null을 반환하지 말고 길이가 0인 배열을 반환하라.

길이가 0일 수도 있는 배열을 반환하는 올바른 방법

public Cheese[] getCheeses(){
	return cheesesInStock.toArray(new Cheese[0]);
}

이 방식이 성능을 떨어뜨릴 것 같다면, 길이 0짜리 배열을 미리 선언해두고 매번 그 배열을 반환해주면 된다. 길이가 0인 배열은 항상 불변이기 때문이다.

최적화 - 빈 배열을 매번 새로 할당하지 않도록 했다.

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

public Cheese[] getCheeses(){
	return cheeseInStock.toArray(EMPTY_CHEESE_ARRAY);
}

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

좋은 웹페이지 즐겨찾기