티스토리 뷰
728x90
반응형
한정적 와일드카드를 사용해 API 유연성을 높이라
- 아이템 28 에서도 나온 얘기이지만 매개변수화 타입은 불공변입니다. 즉 서로 다른 타입 Type1과 Type2가 있을 때 List<Type1>은 List<Type2>의 하위 타입도 상위 타입도 아닙니다.
- 조금 더 쉽게 표현하면 List<String>은 List<Object>의 하위타입도 아니고 상위 타입도 아닙니다. 그냥 타입이 다르며, List<Object>는 모든 것을 담을 수 있지만 List<String>은 문자열만 담을 수 있기에 List<String>은 List<Object>가 하는일을 제대로 수행하지 못합니다.
💡결함이 있는 메서드(컴파일 에러 발생)
- Integer는 Number의 하위 타입이니 논리적으로는 문제가 없을거 같지만 실제로는 컴파일 에러가 발생합니다. 원인은 매개변수화 타입이 불공변이기 때문에 Number로 변환할 수 없다는 것입니다.
public class Stack<E> {
private E[] elements;
private int size;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
this.elements = (E[]) new Object[DEFAULT_INITIAL_CAPACITY];
}
public void push(E o) {
ensureCapacity();
elements[size++] = o;
}
public E pop() {
if (size == 0) {
throw new EmptyStackException();
}
E result = elements[--size];
elements[size] = null;
return result;
}
// 예제 메서드
public void pushAll(Iterable<E> src) {
for(E e : src) push(e);
}
private void ensureCapacity() {
if (elements.length == size) {
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
}
public class EffectiveJavaApplication {
public static void main(String[] args) throws Exception {
Stack<Number> stack = new Stack<>();
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
// java: 호환되지 않는 유형: java.util.List<java.lang.Integer>
// java.lang.Iterable<java.lang.Number>로 변환할 수 없습니다.
stack.pushAll(integers);
}
}
💡한정적 와일드 카드 타입을 적용한 메서드
- 매개변수의 타입을 Iterable<? extends E>로 와일드 카드 타입을 적용하면 컴파일 에러가 사라집니다.
public void pushAll(Iterable<? extends E> src) {
for(E e : src) push(e);
}
💡생산자 매개변수화 타입과 소비자 매개변수화 타입
- 매개변수화 타입 E가 생산자라면 <? extends E>를 사용하고, 소비자라면 <? super E>를 사용합니다.
<? extends E> // 생산자
<? super E> // 소비자
💡생산자 매개변수화 타입과 소비자 매개변수화 타입 예제
- 생산자는 extends로 하위 타입 유연성을 높이고, 소비자라면 super로 상위 타입 유연성을 높여야 합니다.
- 참고: 반환타입은 한정적 와일드 카드 타입(Collection<? extends E>)을 사용하면 안됩니다.
- 유연성을 높여주기는 커녕 클라이언트 코트에서도 와일드 카드 타입을 써야하기 때문입니다.
public class Stack<E> {
private E[] elements;
private int size;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
public Stack() {
this.elements = (E[]) new Object[DEFAULT_INITIAL_CAPACITY];
}
// 소비자 매개변수화 타입
public Collection<E> popAll(Collection<? super E> o) {
while (size != 0) {
E result = elements[--size];
elements[size] = null;
o.add(result);
}
return (Collection<E>) o;
}
// 생산자 매개변수화 타입
public void pushAll(Iterable<? extends E> src) {
for(E e : src) push(e);
}
}
public class EffectiveJavaApplication {
public static void main(String[] args) throws Exception {
Stack<Number> stack = new Stack<>();
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
// 생산자
stack.pushAll(integers);
// 소비자
stack.popAll(new ArrayList<>()).stream().forEach(System.out::print); // 54321
}
}
💡정리
- 와일드 카드 타입을 적용하면 API가 유연해집니다. 단, 타입을 정확히 지정해야 하는 상황에서는 와일드 카트 타입을 쓰지 말아야 합니다.
- 생산자 매개변수화 타입이라면 <? extends E>
- 소비자 매개변수화 타입이라면 <? super E>
- Comparable과 Comparator는 모두 소비자입니다. Comparable<? super E>
- 메서드 선언 타입에 타입 매개변수가 한 번만 등장하면 와일드 카드를 사용하는게 좋습니다.
728x90
반응형
'스터디 > 이펙티브 자바' 카테고리의 다른 글
이펙티브 자바 - Item33. 타입 안전 이종 컨테이노를 고려하라. (0) | 2022.07.23 |
---|---|
이펙티브 자바 - Item32. 제네릭과 가변인수를 함께 쓸 때는 신중하라. (0) | 2022.07.23 |
이펙티브 자바 - Item30. 이왕이면 제네릭 메서드로 만들라. (0) | 2022.07.21 |
이펙티브 자바 - Item29. 이왕이면 제네릭 타입으로 만들라. (0) | 2022.07.20 |
이펙티브 자바 - Item28. 배열보다는 리스트를 사용하라. (0) | 2022.07.18 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
TAG
- redis sorted set
- 람다 표현식
- JDK Dynamic Proxy와 CGLIB의 차이
- 공간 기반 아키텍처
- spring boot excel download paging
- pipe and filter architecture
- 트랜잭셔널 아웃박스 패턴 스프링 부트 예제
- @ControllerAdvice
- java ThreadLocal
- spring boot 엑셀 다운로드
- redis sorted set으로 대기열 구현
- spring boot redisson sorted set
- transactional outbox pattern spring boot
- spring boot redisson 분산락 구현
- 레이어드 아키텍처란
- microkernel architecture
- 자바 백엔드 개발자 추천 도서
- spring boot redisson destributed lock
- pipeline architecture
- 서비스 기반 아키텍처
- redis 대기열 구현
- spring boot redis 대기열 구현
- service based architecture
- polling publisher spring boot
- 트랜잭셔널 아웃박스 패턴 스프링부트
- spring boot excel download oom
- space based architecture
- spring boot poi excel download
- java userThread와 DaemonThread
- transactional outbox pattern
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
글 보관함