Search
🙊

이펙티브 자바:: 아이템 26 <로 타입은 사용하지 말라>

Intro::

이펙티브 자바 정리본입니다.

결론

로 타입을 사용하면 런타임에 예외가 일어날 수 있습니다. 그러니 되도록이면 사용하지 말아야 합니다.
로 타입은 제네릭이 도입되기 이전 코드와의 호환성을 의해 제공될 뿐입니다.
예시로 Set<Object>와 Set<?>은 안전하지만, 이들의 로 타입인 Set은 안전하지 않습니다.

로 타입이란?

클래스와 인터페이스 선언에 타입 매개변수가 쓰이면, 이를 제네릭 클래스 혹은 제네릭 인터페이스라고 하며, 이를 통틀어서 제네릭 타입이라고 합니다.
// 원소 타입이 String인 리스트를 뜻하는 매개변수화 타입 // String 이 정규 타입 매개변수 E에 해당하는 실제 타입 매개변수입니다. List<String> list ....
Java
복사
로 타입이란 제네릭 타입에서 타입 매개변수를 전혀 사용하지 않을 때를 말합니다. 로 타입은 타입 선언에서 제네릭 타입 정보가 전부 지워진 것처럼 동작하는데, 제네릭이 도래하기 전 코드와 호환되도록 하기 위한 궁여지책입니다.
로 타입을 쓰면 제네릭이 안겨주는 안전성과 표현력을 모두 잃게 됩니다.

그럼 로타입은 뭐에 쓰라는 걸까??

기존 코드를 모두 수용하면서(제네릭을 사용하기 전) 제네릭을 사용하는 새로운 코드와도 호환되기 위해 사용합니다.
List<Object>처럼 임의 객체를 허용하는 매개변수화 타입에서의 로 타입은 사용해도 괜찮다.
로 타입인 List와 매개변수화 타입인 List<Object>의 차이는 다음과 같다.
List
List<Object>
제네릭 타입에서 완전 발을 뺀 상태
모든 타입을 허용한다는 의사를 컴파일러에 명확히 전달
List<Object> 같은 매개변수화 타입을 사용할 때와 달리 List 같은 로 타입을 사용하면 타입 안전성을 읽게 됩니다.
// 코드 26-4 런타임에 실패한다. - unsafeAdd 메서드가 로 타입(List)을 사용 (156-157쪽) public class Raw { public static void main(String[] args) { List<String> strings = new ArrayList<>(); unsafeAdd(strings, Integer.valueOf(42)); String s = strings.get(0); // 컴파일러가 자동으로 형변환 코드를 넣어준다. } /** * 런타임 단에서 에러 발생 * @param list * @param o */ private static void unsafeRawAdd(List list, Object o) { list.add(o); } /** * 컴파일러단에서 에러 발생 * @param list * @param o */ private static void unsafeAdd(List<Object> list, Object o) { list.add(o); } }
Java
복사

원소의 타입을 몰라도 되는 경우

// 로 타입을 사용하는 경우 static int numElementsInCommon(Set s1, Set s2) { int result = 0; for (Object o : s1) { if (s2.contains(o)) { result++; } } return result; }
Java
복사
로타입을 사용하면 동작은 하지만 안전하지 않습니다. 따라서 비한정적 와일드카드 타입을 대신 사용하는 게 좋습니다.
// 비한정적 와일드카드 타입을 사용하는 경우 static int numElementsInCommon(Set<?> s1, Set<?> s2) { int result = 0; for (Object o : s1) { if (s2.contains(o)) { result++; } } return result; }
Java
복사

비한정적 와일드 카드 타입 특징

어떤 원소도(null 이외에는) 넣을 수 없습니다. 다른 원소를 넣으려 하면 컴파일 에러가 발생합니다.

로 타입을 사용하는 예외 케이스

class 리터럴
// 허용됨 List.class String[].class int.class // 허용되지 않음 List<String>.class List<?>.class
Java
복사
instanceof 연산자
런타임에는 제네릭 타입 정보가 지워지므로 instanceof 연산자는 비한정적 와일드카드 타입 이외의 매개변수화 타입에는 적용할 수 없습니다.
if (o instanceof Set) { Set<?> s = (Set<?>) o; ... }
Java
복사

References::

이펙티브 자바 / 조슈아 블로크 지음 (프로그래밍 인사이트)