-
[Effective Java] 아이템31: 한정적 와일드카드를 사용해 API 유연성을 높이라Language/Java 2022. 8. 6. 09:34
아이템 28에서 이야기했듯 매개변수화 타입은 불공변(invariant)이다.
즉 서로 다른 타입 Type1과 Type2가 있을 때 List<Type1>은 List<Type2>의 하위 타입도 상위 타입도 아니다.
하지만 때론 불공변 방식보다 유연한 무언가가 필요하다.
유연성을 높이기 위해, 원소의 생산자(producer)나 소비자(consumer)용 입력 매개변수에 와일드카드 타입을 사용하자.
✔️ PECS
팩스(PECS) 란, producer-extends, consumer-super 를 의미한다.
- 매개변수화 타입 T가
생산자
라면<? extends T>
를 사용한다. - 매개변수화 타입 T가
소비자
라면<? super T>
를 사용한다.
📍 생산자 매개변수에 와일드카드 타입 적용
그 동안 살펴본 예제 중 생산자 매개변수에 와일드카드 타입을 적용해보자.
// Stack public void pushAll(Iterable<? extends E> src) { for (E e : src) push(e); }
public Chooser(Collection<? extends T> choices) { choiceList = new ArrayList<>(choices); }
public static <E> Set<E> union(Set<? extends E> s1, Set<? extends E> s2)
*단, 반환 타입에는 한정적 와일드카드 타입을 사용하면 안 된다.
유연성을 높여주기는커녕 클라이언트 코드에서도 와일드카드 타입을 써야 하기 때문이다.📍 소비자 매개변수에 와일드카드 적용
다음은 소비자 매개변수에 와일드카드 타입을 적용한 예시이다.
public void popAll(Collection<? super E> dst) { while (!isEmpty()) dst.add(pop()); }
✔️ Comparable, Comparator
아이템 30에서의 max 메서드에도 적용해보자.
public static <E extends Comparable<? super E>> E max(List<? extends E> list)
Comparable
은 언제나 소비자다.Comparator
도 마찬가지이다.- Comparable<E> →
Comparable<? super E>
- Comparator<E> →
Comparator<? super E>
✔️ 타입 매개변수 vs 와일드카드
타입 매개변수와 와일드카드를 모두 사용할 수 있는 경우에는 어떤 것을 사용해야 할까?
// 와일드카드 타입을 실제 타입으로 바꿔주는 private 도우미 메서드 private static <E> void swapHelper(List<E> list, int i, int j) { list.set(i, list.set(j, list.get(i))); } public static void swap(List<?> list, int i, int j) { swapHelper(list, i, j); }
- 메서드 선언에 타입 매개변수가 한 번만 나오면 와일드카드로 대체하라.
- 이때 비한정적 타입 매개변수라면 비한정적 와일드카드로 바꾸고, 한정적 타입 매개변수라면 한정적 와일드카드로 바꿔라.
- 그렇지 않은 경우는 타입 매개변수를 사용하라.
핵심 정리
- 조금 복잡하더라도 와일드카드 타입을 적용하면 API가 훨씬 유연해진다.
- 그러니 널리 쓰일 라이브러리를 작성한다면 반드시 와일드카드 타입을 적절히 사용해줘야 한다.
- PECS 공식을 기억하자.
즉, 생산자(producer)는 extends를, 소비자(consumer)는 super를 사용한다.
Comparable과 Comparator는 모두 소비자라는 사실도 잊지 말자.
728x90'Language > Java' 카테고리의 다른 글
[Effective Java] 아이템33: 타입 안전 이종 컨테이너를 고려하라 (0) 2022.08.10 [Effective Java] 아이템32: 제네릭과 가변인수를 함께 쓸 때는 신중하라 (0) 2022.08.09 [Effective Java] 아이템30: 이왕이면 제네릭 메서드로 만들라 (0) 2022.08.06 [Effective Java] 아이템29: 이왕이면 제네릭 타입으로 만들라 (0) 2022.08.06 [Effective Java] 아이템28: 배열보다는 리스트를 사용하라 (0) 2022.07.30 - 매개변수화 타입 T가