[Effective Java 3/e] 아이템 26 - 로 타입은 사용하지 말라


아이템 26 - 로 타입(raw type)은 사용하지 말라

로 타입 - 타입 매개변수를 전혀 사용하지 않은 것

  • List 의 로 타입은 List
  • 로 타입을 쓰면 제네릭이 안겨주는 안전성과 표현력을 모두 잃게 된다.

컬렉션의 로 타입- 따라 하지 말 것

//Stamp 인스턴스만 취급한다.
private final Collection stamps = ...;

//실수로 동전을 넣는다.
stamps.add(new Coin(...));  //unchecked call 경고를 내뱉는다.

반복자의 로 타입 - 따라 하지 말 것

for (Iterator i = stamps.iterator(); i.hasNext();) {
  Stamp stamp = (Stamp) i.next(); //ClassCastException을 던진다.
  stamp.cancel();
}

매개변수화된 컬렉션 타입 - 타입 안전성 확보

private final Collection<Stamp> stamps = ...;
  • 잘못 된 타입의 인스턴스를 넣으려 하면 컴파일 오류가 발생

잘못된 예 - 모르는 타입의 원소도 받는 로 타입을 사용했다

static int numElementsInCommon(Set s1, Set s2) {
  int result = 0;
  for (Object o1 : s1)
    if (s2.contains(o1))
      result++;
  return result;
}

비한정적 와일드카드 타입을 사용하라 - 타입 안전하며 유연하다

static int numElementsInCommon(Set<?> s1, Set<?> s2) {...}

로 타입을 써야 하는 예외 상황

  • class 리터럴에는 로 타입을 써야 한다.
    • 허용 - List.class, String[].class
    • 불허용 - List.class, List<?>.class
  • 제네릭 타입에 instanceof 사용

로 타입을 써도 좋은 예 - instanceof 연산자

if (o instaceof Set) {  // 로 타입
  Set<?> s = (Set<?>) o;  // 와일드카드 타입
}
  • o의 타입이 Set임을 확인한 다음 와일드카드 타입인 Set<?>로 형변환해야 한다.
    • 이는 검사 형변환(checked cast)이므로 컴파일러 경고가 뜨지 않는다.

정리

  • 로 타입을 사용하면 런타임에 예외가 일어날 수 있으니 사용하면 안 된다.
  • Set는 어떤 타입의 객체도 저장할 수 있는 매개변수화 타입
  • Set<?>는 모종의 타입 객체만 저장할 수 있는 와일드카드 타입
  • Set은 제네릭 타입 시스템에 속하지 않는다.
  • Set와 Set<?>는 안전하지만, 로 타입인 Set은 안전하지 않다.