📌 5장 : 제네릭
아이템 26. 로 타입은 사용하지 말라
- 제네릭 타입(generic type)
- 제네릭 클래스와 제네릭 인터페이스 : 클래스와 인터페이스 선언에 타입 매개변수가 쓰이는 경우
- 제네릭 타입은 일련의 매개변수화 타입을 정의한다.
- List : 원소의 타입이 String인 리스트를 뜻하는 매개변수화 타입
- String은 정규 타입 매개변수 E에 해당하는 실제 타입 매개변수
- 제네릭 타입을 정의하면, 로 타입(raw type)도 정의한다.
- 로 타입(raw type)
- 제네릭 타입에서 타입 매개변수를 사용하지 않은 경우
- List의 로 타입은 List
- 오류를 발생하고나서 런타임에 문제를 겪는 경우
// 컬렉션의 로 타입
private final Collection stamps = ...;
// 반복자의 로 타입
for (Iterator i = stamps.iterater(); i.hasNext(); ) {
Stamp stamp = (Stamp) i.next(); // ClassCastException을 던진다.
stamp.cancel();
}
- 제네릭을 활용하면 정보를 타입 선언 자체에 녹일 수 있다.
private final Collection<Stamp> stamps = ...;
- 로 타입을 쓰는 이유는?
- 기존 코드와 제네릭을 사용하는 새로운 코드가 돌아가도록 해야하는 호환성 때문에
- List 같은 로 타입은 사용하면 안되지만, List 같은 임의 객체를 허용하는 매개변수 타입은 사용 가능하다.
아이템 27. 비검사 경고를 제거하라- 모든 비검사 경고는 런타임에 ClassCstException을 일으킬 수 있는 잠재적 가능성이 있기 때문에 제거 해야 한다.
- 경고를 제거할 수 없지만 타입이 안전하다고 확신할 수 있는경우 : @SuppressWarnings("unchecked") 애너테이션을 달아서 경고를 숨긴다.
- 개별 지역변수 선언부터 클래스 전체까지 어디에나 선언할 수 있지만, 가능한 좁은 범위에 적용한다.
아이템 28. 배열보다는 리스트를 사용하라- 배열과 제네릭 타입의 차이점
- 배열은 공변(covariant) : Sub가 Super의 하위 타입이면 Sub[]은 Super[]의 하위 타입이 되는 것처럼 같이 변한다.
- 제네릭은 불공변(invariant) : 타입 Type1, Type2가 있을 경우, List은 List의 하위 타입도 상위 타입도 아니다.
- 배열은 실체화가 가능하다.
- 런타임에도 자신이 담기로 한 원소의 타입을 인지하고 확인한다.
- 제네릭은 타입 정보가 런타임에 소거된다. (원소 타입을 컴파일타입에만 검사한다.)
- 배열은 제네릭 타입, 매개변수화 타입, 타입 매개변수로 사용할 수 없다.
- 둘을 같이 쓰다가 컴파일 오류가 생기면 가장 먼저 배열을 리스트로 대체하는 방법을 사용한다.
아이템 29. 이왕이면 제네릭 타입으로 만들라- 클라이언트에서 직접 형변환하는 타입보다 제네릭 타입이 더 안전하고 사용이 간단하다.
- 새로운 타입을 설계하는 경우 형변환 없이 사용할 수 있도록 제네릭 타입으로 만들어야 하는 경우가 많다.
아이템 30. 이왕이면 제네릭 메서드로 만들라- 클라이언트에서 입력 매개변수와 반환값을 명시적으로 형변환하는 메서드보다 제네릭 메서드가 더 안전하고 사용이 간단하다.
- 타입처럼 메서드도 형변환 없는 것이 편하기 때문에, 제네릭 메서드를 만들도록 한다.
아이템 31. 한정적 와일드카드를 사용해 API 유연성을 높이라- 불공변 방식보다 유연한 상황이 필요한 경우 : 매개변수화 타입이 불공변인 경우 생기는 오류
- 한정적 와일드카드 타입이라는 특별한 매개변수화 타입을 사용한다.
아이템 32. 제네릭과 가변인수를 함께 쓸 때는 신중하라
- 가변 인수는 메서드를 호출하면 가변 인수를 담기 위한 배열이 자동으로 생성된다.
- 배열이 클라이언트에 노출이 되어 매개변수에 제네릭이나 매개변수화 타입이 포함되면 컴파일 경고가 발생하게 된다.
- 매개변수 인수 메서드를 호출할 경우, 매개변수가 실체화 불가 타입으로 추론될 때 경고 형태
- 매개변수화 타입의 변수가 타입이 다른 객체를 참조하면 힙 오염이 발생한다.
warning: [unchecked] Possible heap pollution from
parameterized vararg type List<String>
- 자바 7에서 @SafeVarargs 애너테이션 추가 : 메서드 작성자가 타입 안전함을 보장하는 장치
- 제네릭 varargs 매개변수를 안전하게 사용하는 메서드
@SafeVarargs
static <T> List<T> flatten(List<? extends T>... lists) {
List<T> result = new ArrayListo();
for (List<? extends T> list : lists)
result.addAlKlist);
return result;
}
- 제네릭 varargs 메서드가 안전한 기준
- varargs 매개변수 배열에 아무것도 저장하지 않는다.
- 그 배열(혹은 복제본)을 신뢰할 수 없는 코드에 노출하지 않는다.
아이템 33. 타입 안전 이종 컨테이너를 고려하라
- 제네릭 형태에서는 한 컨테이너가 다룰 수 있는 타입 매개변수의 수가 고정되어 있다.
- 컨테이너 자체가 아니라 키를 타입 매개변수로 바꾸면 제약이 없는 타입 안전 이종 컨테이너를 만들 수 있다.
- 타입 토큰 : 타입 안전 이종 컨테이너는 Class를 키로 사용한다.
'ETC > 이펙티브자바' 카테고리의 다른 글
[이펙티브 자바] 7장 : 람다와 스트림 (0) | 2023.03.20 |
---|---|
[이펙티브 자바] 6장 : 열거 타입과 애너테이션 (0) | 2023.03.20 |
[이펙티브 자바] 4장 : 클래스와 인터페이스 (0) | 2023.03.19 |
[이펙티브 자바] 3장 : 모든 객체의 공통 메서드 (0) | 2023.01.16 |
[이펙티브 자바] 2장 : 객체 생성과 파괴 (0) | 2023.01.02 |