ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [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

    댓글

Designed by Tistory.