📌 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를 키로 사용한다.

+ Recent posts