[Effective Java] item 54 : null이 아닌, 빈 컬렉션이나 배열을 반환하라

DEINGVELOP·2023년 3월 26일
0

Effective Java

목록 보기
18/19

null값 반환을 피해야 하는 이유

💬 한 줄 요약
null을 반환하는 API는 사용하기 어렵고, 오류 처리 코드도 늘어난다. 성능이 더 좋은 것도 아니다.

다음은 컬렉션이 비었다면 null을 반환하는 코드이다.

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

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

클라이언트 입장

위와 같은 코드에서 만약 null값을 반환하게 된다면, 클라이언트는 이 null 상황을 처리하는 코드를 추가로 작성해야 한다.

ex)

List<Cheese> cheeses = shop.getCheeses();
if(cheeses != null && cheeses.contains(Cheese.STILTON))
	System. out. printIn("좋았어, 바로 그거야广》;

클라이언트에서 위와 같이 방어하는 코드를 항상 써야 하며, 이걸 빼먹으면 오류가 발생할 수 있따.
실제 객체가 0개일 가능성이 거의 없는 상황에서는 (계속 방치되다가) 수년 뒤에야 오류가 발생하기도 한다.

개발자

Collection
null을 반환하려면, 반환하는 쪽에서도 이 상황을 특별히 취급해줘야 해서 코드도 더 복잡해진다. 따라서 빈 컬렉션을 반환하자.

배열
절대 null을 반환하지 말고, 다음과 같이 길이가 0인 배열을 반환하라.

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

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

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

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

단순히 성능을 개선할 목적이라면 다음과 같이 toArray에 넘기는 배열을 미리 할당하는 건 추천하지 않는다. 오히려 성능이 떨어진다는 연구 결과가 있다.

return cheesesInStock.toArray(new Cheese[cheesesInStock.size()]);

반박 의견 : 빈 컨테이너를 할당하는 데에도 비용이 드니, null 반환이 낫다!

👉🏻 이는 두 가지 면에서 틀린 주장이다.

1. 성능 차이 거의 없음

성능 분석 결과 이 할당이 성능 저하의 주범이라고 확인되지 않는 한, 이 정도의 성능 차이는 신경 쓸 수준이 못 된다.

확실한 해법

단, 작은 가능성으로 사용 패턴에 따라 빈 컬렉션 할당이 성능을 눈에 띄게 떨어뜨릴 수도 있다. 이는 다행히 매번 똑같인 빈 '불변' 컬렉션을 반환하는 것으로 간단히 해결이 가능하다. 알다시피 불변 객체는 자유롭게 공유해도 안전하다.

  • Collections.emptySet
  • Collections.emptyMap

단, 이 역시 최적화에 해당되니 꼭 필요할 때에만 사용하자. 그리고 최적화가 필요하다고 판단되면, 수정 전과 후의 성능을 측정하여 실제로 성능이 개선되는지 꼭 확인하자.

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

2. 빈 컬렉션과 배열은 굳이 새로 할당하지 않고도 반환할 수 있다.

대부분의 상황에서는 아래와 같이 하면 된다.

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

0개의 댓글