-
아이템31. 한정적 와일드카드를 사용해 API 유연성을 높이라Java/이펙티브 자바 2023. 10. 31. 16:32
핵심정리 - Chooser와 Union API 개선
PECS : Producer-Extends, Consumer-Super
- Producer-Extends
ㆍObject의 컬렉션 Number나 Integer를 넣을 수 있다.
ㆍNumber의 컬렉션에 Integer를 넣을 수 있다.
- Consumer-Super
ㆍInteger의 컬렉션의 객체를 꺼내서 Number의 컬렉션에 담을 수 있다.
ㆍNumber나 Integer의 컬렉션의 객체를 꺼내서 Object의 컬렉션에 담을 수 있다.
- 예시)
// 코드 31-2 E 생산자(producer) 매개변수에 와일드카드 타입 적용 (182쪽) public void pushAll(Iterable<? extends E> src) { for (E e : src) { push(e); } }
ㆍNumber 라면 Integer, Double 등등 이 들어갈 수 있다.
ㆍ즉, 하위 타입으로 확장 가능하다. ( 최상위 타입이 한정되어 있으므로 상위 한정 )// 코드 31-4 E 소비자(consumer) 매개변수에 와일드카드 타입 적용 (183쪽) public void popAll(Collection<? super E> dst) { while(!isEmpty()) { dst.add(pop()); } }
ㆍNumber 라면 Object Collection 안에 값을 넣을 수 있다.
ㆍ즉, 상위 타입으로 확장 가능하다. ( 최하위 타입이 한정되어 있으므로 하위 한정 )
핵심정리 - Comparator 와 Comparable 은 소비자
- Comparable을 직접 구현하지 않고, 직접 구현한 다른 타입을 확장한 타입을 지원하려면 와일드카드가 필요하다.
ㆍScheduledFuture → Delayed → Comparable<T>
ㆍScheduledFuture는 Comparable을 직접 구현하지 않았지만, 그 상위 타입(Delayed)이 구현하고 있다.
- Producer - extends
public Chooser(Collection<? extends T> choices) { chiceList = new ArrayList<>(choices); } public static void main(String[] args) { List<Integer> intList = List.of(1,2,3,4,5,6); Chooser<Number> chooser = new Chooser<>(intList); }
public static <E> Set<E> union(Set<? extends E> s1, Set<? extends E> s2) { Set<E> result = new HashSet<>(s1); result.addAll(s2); return result; } public static void main(String[] args) { Set<Integer> integers = new HashSet<>(); integers.add(1); integers.add(3); integers.add(5); Set<Double> doubles = new HashSet<>(); doubles.add(2.0); doubles.add(4.0); doubles.add(6.0); Set<Number> numbers = union(integers, doubles); }
- Consumer - super
public static <E extends Comparable<? super E>> E max(List<? extends E> list) { ... } public static void main(String[] args) { List<IntegerBox> list = new ArrayList<>(); list.add(new IntegerBox(1, "phm")); list.add(new IntegerBox(2, "phm2")); System.out.println(max(list)); }
ㆍIntegerBox는 Comparable을 구현하지 않았다. 하지만 상속하는 Box가 Comparable을 구현했기에 사용가능
핵심정리 - 와일드카드 활용 팁
- 메서드 선언에 타입 매개변수가 한 번만 나오면 와일드카드로 대체하라
ㆍ한정적 타입이라면 한정적 와일드카드로
ㆍ비한정적 타입이라면 비한정적 와일드카드로
- 주의!
ㆍ비한정적 와일드카드(?)로 정의한 타입에는 null을 제외한 아무것도 넣을 수 없다.
- E, T 같은 경우는 특정한 타입, ? 같은 경우는 불특정한 임의의 타입
Box<?> myBox = new IntegerBox(10, "phm"); myBox.change(100); //컴파일에러 - myBox가 무슨 타입인지 모르기때문
public static <E> void swap(List<E> list, int i, int j) { // public static void swap(List<?> list, int i, int j) { list.set(i, list.set(j, list.get(i))); // swapHelper(list, i, j); }
ㆍ꺼내는건 가능하지만 넣는건 null 말고는 불가능
ㆍ그렇기에 Helper 메서드를 쓸바에 위와 같은 방식 추천
완벽공략 - 타입추론
- 타입을 추론하는 컴파일러의 기능
- 모든 인자의 가장 구체젝인 공통 타입 (most specific type)
- 제네릭 메서드와 타입 추론 : 메서드 매개변수를 기반으로 타입 매개변수를 추론할 수 있다.
- 제네릭 클래스 생성자를 호출할 때 다이아몬드 연산자 <>를 사용하면 타입을 추론한다.
ArrayList<Box<Integer>> listOfIntegerBoxes = new ArrayList<>(); List<String> stringlist = Collections.emptyList(); List<Integer> integerlist = Collections.emptyList();
- 자바 컴파일러는 "타겟 타입"을 기반으로 호출하는 제네릭 메서드의 타입 매개변수를 추론한다.
ㆍ자바 8에서 "타겟 타입"이 "메서드의 인자"까지 확장되면서 이전에 비해 타입 추론이 강화되었다.
'Java > 이펙티브 자바' 카테고리의 다른 글
아이템33. 타입 안전 이종 컨테이너를 고려하라. (0) 2023.11.09 아이템 32. 제네릭과 가변인수를 함께 쓸 때는 신중하라. (0) 2023.11.05 아이템29 & 아이템30 (0) 2023.09.28 아이템28. 배열보다는 리스트를 사용하라 (0) 2023.09.23 아이템 27. 비검사 경고를 제거하라 (0) 2023.09.21