Notice
Recent Posts
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
Tags
- 선형자료구조
- 깊이우선탐색
- Simple Brute-Force Algorithm
- 고급정렬
- 우선순위 큐
- Queue
- Adv. recursive function
- binary search
- basic data-structure
- 이진탐색
- 완전탐색
- dfs
- Stack
- 매개 변수 탐색
- 간단한 완전탐색
- 알고리즘잡스
- 힙
- 큐
- 동적계획법
- 개념
- hint
- 내돈후기
- heap
- 스택
- Divide and Conquer
- 정렬
- parametric search
- Advanced Sort
- 기본자료구조
- Sort
- Today
- Total
루시와 프로그래밍 이야기
ITEM31. 한정적 와일드카드를 사용해 API 유연성을 높이라 본문
- 매개변수화 타입은 불공변(invariant)이다.
- 서로 다른 타입 Type1과 Type2가 있을 때 List<Type1>은 List<Type2>의 하위 타입도 상위 타입도 아니다.
- List<String>은 List<Object>가 하는 일을 제대로 수행하지 못하니 하위 타입이 될 수 없다.
(리스코프 치환 원칙에 어긋난다.) ITEM10 - 때로는 불공변 방식보다 유연한 방식이 필요하다.
Stack의 API
public class Stack<E> {
public Stack();
public void push(E e);
public E pop();
public boolean isEmpty();
}
여기에 일련의 원소를 스택에 넣는 메서드를 추가
public class Stack<E> {
public void pushAll(Iterable<E> src) {
for (E e : src) {
push(e);
}
}
}
Integer 는 Number 의 하위 타입이니 pushAll(Integer타입값)이 잘 동작할 것 같다.
import java.util.Stack;
class Example {
public static void main(String[] args) {
Stack<Number> numberStack = new Stack<>();
Iterable<Integer> integers;
numberStack.pushAll(integers);
}
}
- 실제 매개 변수화 타입이 불공변이기 때문에 오류 메시지를 내뱉는다.
- 자바는 이런 상황에 대처할 수 있는 한정적 와일드카드 타입이라는 특별한 매개변수화 타입을 지원한다.
와일드카드 타입 적용
class Example {
public void pushAll(Itrable<? extends E> src) {
for (E e : src) {
push(e);
}
}
}
- 유연성을 극대화하려면 원소의 생산자나 소비자용 입력 매개변수에 와일드카드 타입을 사용해야 한다.
- 입력 매개변수가 생산자와 소비자 역할을 동시에 한다면 와일드 카드 타입을 써도 좋을 게 없다.
- 타입을 정확히 지정해야 하는 상황으로, 이때는 와일드 카드 타입을 쓰지 않아야 한다.
펙스(PECS): producer-extends, consumer-super
- 와일드카드 타입을 써야하는지에 대한 상황을 분별할 수 있는 기준
- 매개변수화 타입 T가 생상자인경우 <? extends T>를 사용하고, 소비자인 경우 <? super T>를 사용해야 한다.
- Stack 예
- pushAll의 src 매개변수는 Stack이 사용할 E 인스턴스를 생산하므로 src의 적절한 타입은 Iterable<? extends E>이다.
- popAll의 dst 매개변수는 Stack으로부터 E 인스턴스를 소비(RETURN 반환)하므로 dst의 적절한 타입은 Collection<? super E> 이다.
- pushAll의 src 매개변수는 Stack이 사용할 E 인스턴스를 생산하므로 src의 적절한 타입은 Iterable<? extends E>이다.
- PECS 공식은 와일드카드 타입을 사용하는 기본원칙
ITEM30 의 union 코드 수정
class Example {
public static <E> Set<E> union(Set<? extends E> si, Set<? extends E> s2) {
Set<E> result = new HashSet<>(sl);
result.addAll(s2);
return result;
}
}
class Client {
public static void main(String[] args) {
Set<Integer> integers = Set.of(1, 3, 5);
Set<Double> doubles = Set.of(2.0, 4.0, 6.0);
Set<Number> numbers = union(integers, doubles);
}
}
정리
- 조금 복잡하더라도 와일드 카드 타입을 적용하면 API가 훨씬 유연해진다.
- 널리 쓰일 라이브러리를 작성한다면 반드시 와일드카드 타입을 적절히 사용해야 한다.
- PECS 공식을 기억하자
- 생산자(producer)는 extends를 소비자(consumer)는 super를 사용한다.
- Comparable과 Comparator는 모두 소비자라는 사실을 잊지 않아야 한다.
'스터디 > 이펙티브 자바' 카테고리의 다른 글
ITEM33. 타입 안전 이종 컨테이너를 고려하라 (0) | 2022.10.13 |
---|---|
ITEM32. 제네릭과 가변인수를 함께 쓸 때는 신중하라 (0) | 2022.10.13 |
ITEM30. 이왕이면 제네릭 메서드로 만들라 (0) | 2022.10.13 |
ITEM29. 이왕이면 제네릭 타입으로 만들라 (1) | 2022.10.12 |
ITEM14. Comparable을 구현할지 고려하라 (0) | 2022.09.01 |