제네릭은 자바 5부터 사용할 수 있다. 제네릭을 지원하기 전에는 컬렉션에서 객체를 꺼낼 때마다 형변환을 해야 했다.

반면 제네릭을 사용하면 컬렉션이 담을 수 있는 타입을 컴파일러에 알려주게 된다.

그래서 컴파일러는 알아서 형변환 코드를 추가할 수 있게 되고, 엉뚱한 타입의 객체를 넣으려는 시도를 컴파일 과정에서 차단하게 된다.

26. Raw 타입은 사용하지 말라

용어 정리

클래스와 인터페이스 선언에 타입 매개변수가 쓰이면 이를 제네릭 클래스 혹은 제네릭 인터페이스라 한다.

예컨데 List 인터페이스는 원소의 타입을 나타내는 타입 매개변수 E를 받는다. 그래서 이 인터페이스의 완전한 이름은 List<E>이지만 짧게 그냥 List라 쓴다.

각각의 제네릭 타입은 일련의 매개변수화 타입을 정의한다. 먼저 클래스 이름이 나오고, 이어서 꺽쇠괄호 안에 실제 타입 매개변수들을 나열한다. (ex. List<String>는 원소의 타입이 String인 매개변수화 타입이다)

마지막으로 제네릭 타입을 하나 정의하면 그에 딸린 로 타입(raw type)도 함께 정의된다.

로 타입이란 제네릭 타입에서 타입 매개변수를 전혀 사용하지 않을 때를 말한다. 예컨대 List<E>의 로 타입은 List이다.

로 타입은 타입 선언에서 제네릭 타입 정보가 전부 지워진 것처럼 동작하는데, 제네릭이 도래하기 전 코드와 호환되도록 하기 위한 궁여지책이라 할 수 있다.

제네릭 타입이 생기기 전에는 이런 식으로 사용되었다.

private final Collection stamps = ...;

이 컬렉션에는 Stamp 인스턴스 뿐만 아니라 다른 타입의 인스턴스도 들어갈 수 있는데, 컬렉션에서 그 원소를 꺼내기 전까지는 오류를 알아채지 못한다.

이 책 전반에서 줄기차게 얘기했지만, 오류는 가능한 한 발생 즉시, 이상적으로는 컴파일할 떄 발견하는 것이 좋다.

위 코드에 주석을 달아 Stamp 인스턴스만 취급하려 해도 컴파일러가 이해하지 못하니 별 소용이 없다.

private final Collection<Stamp> stamps = ...;

이렇게 선언하면 stamps에는 Stamp 인스턴스만 넣어야 함을 컴파일러가 인지하게 된다.

이제 stamps에 엉뚱한 타입의 인스턴스를 넣으려 하면 컴파일 오류가 발생하며 무엇이 잘못됐는지를 정확히 알려준다.

앞에서도 얘기했듯, 로 타입(타입 매개변수가 없는 제네릭 타입)을 쓰는 걸 언어 차원에서 막아 놓지는 않았지만, 절대로 써서는 안 된다.