본문 바로가기
프로그래밍 놀이터/디자인 패턴, 리펙토링

[Effective Java] 바운드 와일드 카드를 사용해서 API 의 유연성을 높이자.

by 돼지왕 왕돼지 2016. 12. 5.
반응형

 [Effective Java] 바운드 와일드 카드를 사용해서 API 의 유연성을 높이자.


API, api 관점, bounded wildcard type, Comparable, Comparator, Consumer, consumer super, Effective JAVA, explicit type parameter, extends, Helper, ieos, in extends, invariant, out super, pecs, Producer, producer extends, Public, raw type, Super, T, t 생산, type, type inference, [Effective Java] 바운드 와일드 카드를 사용해서 API 의 유연성을 높이자., 간단, 거부, 내부, 매개변수, 매개변수화 타입, 메소드, 메소드 선언, 바운드, 바운드 와일드 카드, 반환타입, 불변, 사용자, 생산자, 서브 타입, 소비자, 슈퍼 타입, 언바운드, 언바운드 와일드 카드, 와일드 카드, 와일드 카드 타입, 유연성, 정확한 타입 일치, 제대로 사용, 클라이언트 코드, 타입 추론


-
매개변수화 타입은 불변(invariant) 이다.
서로 다른 두 개의 타입 Type1, Type2 에 대해 List<Type1>, List<Type2> 는 서브 타입도 수퍼 타입도 아니다.


-
매개변수화 타입은 불변이기 때문에, 바운드 와일드 카드 타입(bounded wildcard type)을 사용해야 유연성이 좋다.
예) <E> -> <? extends E> // in 계통
<E> -> <? super E> // out 계통

E 자신도 ? extends E, ? super E 에 속한다.


-
유연성을 극대화하려면, 메소드 인자에 와일드 카드 타입을 사용하자.
만일 메소드 인자가 생산자(producer)와 소비자(consumer) 모두의 입장이라면 와일드 카드 타입의 사용은 좋지 않다.
정확한 타입 일치가 필요하기 때문에 어떤 와일드 카드도 필요 없다.


-
어떤 와일드 카드를 사용할지는 PECS 를 기억하면 된다.
PECS 는 Producer 는 Extends, Consumer 는 Super.
( IEOS (내 맘대로) In 은 Extends, Out 은 Super )
T를 이용해서 무언가를 하는가? -> 소비자
내부의 무언가를 T를 생산하는가? -> 생산자



-
반환타입에는 와일드 카드 타입을 사용하지 말자.
유연성의 제공보다는 클라이언트 코드에서 와일드 카드 타입을 사용해야 하는 문제가 생긴다.
제대로 사용하면 와일드 카드 타입은 클래스 사용자들이 거의 알 수 없다.
메소드에서 반드시 받아야 할 매개변수는 받아들이고, 거부해야 할 매개변수는 거부하도록 해준다.
만일 어떤 클래스를 사용할 때 그 클래스 사용자가 와일드 카드 타입 때문에 고민해야 한다면, 십중팔구 그 클래스의 API 에 뭔가 잘못이 있는 것이다.


-
public static <E> Set<E> union(Set<? extends E> s1, Set<? extends E> s2 );

Set<Integer> integers = ...;
Set<Double> doubles = ...;
Set<Number> numbers = union(integers, doubles);

위 코드는 문제가 없어보이지만, 컴파일 에러가 난다.
컴파일러가 타입추론을 제대로 못하기 때문이다.

이 때는 명시적 타입 매개변수(explicit type parameter) 를 이용해서 어떤 타입을 사용할지 알려줄 수 있다.

Set<Number> numbers = Union.<Number> union(integers, doubles);


-
public static <E> void swap( List<E> list, int i,int j );
public static void swap(List<?> list, int i, int j );

둘 중 더 좋은 녀석은 누구일까?
public API 관점에서는 언바운드 와일드카드를 사용하는 두번째가 좋다. 더 간단하다.
일반적으로는 메소드 선언부에 타입 매개변수가 한번만 나타나면 그것을 와일드 카드로 바꾸면 된다.
만일 그 타입 매개변수가 언바운드면 언바운드 와일드 카드로 바꾸고, 바운드면 바운드 와일드 카드로 바꾼다.

하지만 두번째 방법은 문제가 있다.
<?> 를 사용하였기에 null 이외에는 put 을 할 수 없다.
이 경우 1번의 방법을 helper 로 갖는 function 을 하나 더 가져야 한다.
하지만, public 하게는 raw type 도 받을 수 있어 유연성은 더 좋다.



Summary


메소드 API에 와일드 카드 타입을 사용하면 코드 작성이 조금 어려워지긴 하지만 훨씬 더 유연한 API 를 만들 수 있다.
만일 폭 넓게 사용할 라이브러리를 작성한다면, 와일드 카드 타입을 올바르게 사용해야 한다.
기본 규칙은 PECS ( producer - extends, consumer - super ).
Comparable 과 Comparator 도 소비자라는 것을 잊지 말자.





반응형

댓글