아이템 31 - 한정적 와일드카드를 사용해 API 유연성을 높이라
JAVA ·public class Stack<E> {
...
public void pushAll(Iterable<E> src) {
for(E e : src)
push(E e);
}
}
//불공변 방식인 위와 같이 스택에 pushAll이 정의되어 있다면
//아래의 코드는 오류가 발생한다. 유연한 무언가가 필요하다.
Stack<Number> numberStack = new Stack<>();
Iterable<Integer> integers = List.of(1,2,3);
numberStack.pushAll(integers);
유연성을 극대화하려면 원소의 생산자나 소비자용 입력 매개변수에 와일드카드 타입을 사용해야 한다.
PECS: Producer-Extends, Consumer-Super
- 매개변수화 타입 T가 생산자라면 <? extends T>를 사용하고,소비자라면 <? super T>를 사용하라.
- 클래스 사용자가 와일드카드 타입을 신경 써야 한다면 그 API에 문제가 있을 가능성이 크다.
- Producer-Extends
- Object의 컬렉션 Number나 Integer를 넣을 수 있다.
- Number의 컬렉션에 Integer를 넣을 수 있다.
- Consumer-Super
- Integer의 컬렉션의 객체를 꺼내서 Number의 컬렉션에 담을 수 있다.
- Number나 Integer의 컬렉션의 객체를 꺼내서 Object의 컬렉션에 담을 수 있다.
Comparator와 Comparable은 소비자
- Comparable을 직접 구현하지 않고, 직접 구현한 다른 타입을 확장한 타입을 지원하려면 와일드카드가 필요하다.
- eg) public static <E extends Comparable<? super E» E max(List<? extends E> list)
- ScheduledFuture는 Comparable을 직접 구현하지 않았지만, 그 상위 타입(Delayed)이 구현하고 있다.
와일드카드 활용 팁
- 메서드 선언에 타입 매개변수가 한 번만 나오면 와일드카드로 대체하라.
- 한정적 타입이라면 한정적 와일드카드로
- 비한정적 타입이라면 비한정적 와일드카드로
- 주의
- 비한정적 와일드카드(?)로 정의한 타입에는 null을 제외한 아무것도 넣을 수 없다.