한정적 와일드카드를 사용해 API 유연성을 높이라

김종준·2023년 5월 28일
0

이펙티브자바

목록 보기
26/63

한정적 와일드카드를 사용해 API 유연성을 높이라

매개변수와 타입은 불공변이다.

즉, 서로 다른 타입 Type1과 Type2가 있을 때 ListList<Type2>의 하위 타입도 상위 타입도 아니다.

ListList의 하위 타입이 아니라는 뜻이다.

List에는 어떤 객체든 넣을 수 있지만 List에는 문자열만 넣을 수 있다.

ListList가 하는 일을 제대로 수행하지 못하니 하위 타입이 될 수 없는 것이다.

하지만 때론 불공변 방식보다 유연한 무엇인가가 필요한 경우가 있다.

그래서 자바는 한정적 와일드카드 타입이라는 특별한 매개변수화 타입을 지원한다. ( )

유연성을 극대화하려면 원소의 생산자나 소비자용 입력 매개변수에 와일드카드 타입을 사용해야 한다.

한편, 입력 매개변수가 생산자와 소비자 역할을 동시에 한다면 와일드카드 타입을 사용해도 좋을 게 없다.

타입을 정확히 지정해야 하는 상황으로, 이때는 와일드카드 타입을 쓰지 말아야 한다.

다만 다음 공식을 외워두면 어떤 와일드카드 타입을 써야 하는지 기억하는 데 도움이 될 것이다.

PECS : producer-extends, consumer-super

즉, 매개변수화 타입 T가 생산자라면 <? extends T> 를 사용하고, 소비자라면 <? super T>를 사용하라.

(무언가를 위해 사용되면 생산자, 무언가를 사용하면 소비자)

public void pushAll(Iterable<? extends E> src) {
  for (E e : src) {
    push(e);
  }
}

위의 pushAll의 경우 내부 매서드에서 사용할 E 인스턴스를 생산하므로 src의 적절한 타입은 Iterable<? extends E> 가 될 수 있다.

public void popAll(Collection<? super E> dst) {
  while (!isEmpty()) {
    dst.add(pop());
  }
}

하지만 popAll의 경우 dst 매개변수는 E 인스턴스를 소비하므로 dst의 적절한 타입은 Collection이다.

제대로만 사용한다면 클래스 사용자는 와일드카드 타입이 쓰였다는 사실조차 의식하지 못할 것이다.

받아들여야 할 매개변수를 받고 거절해야 할 매개변수는 거절하는 작업이 알아서 이뤄진다.

클래스 사용자가 와일드카드 타입을 신경 써야 한다면 그 API에 무슨 문제가 있을 가능성이 크다.

그리고 와일드카드와 관련해 논의해야 할 주제가 하나 더 있다.

타입 매개변수와 와일드카드에는 공통되는 부분이 있어서, 메서드를 정의할 때 둘 중 어느 것을 사용해도 괜찮을 때가 많다.

기본 규칙은 이렇다.

메서드 선언에 타입 매개변수가 한 번만 나오면 와일드카드로 대체하라.

이때 비한정 타입 매개변수라면 비한정적 와일드카드로 바꾸고, 한정적 타입 매개변수라면 한정적 와일드카드로 바꾸면 된다.

0개의 댓글