Item 26. 로 타입은 사용하지 말라

이번은 제네릭에 대한 설명이다. 다음과 같이 제네릭 타입을 하나 정의하면 List<E> 이와 함께 로 타입(raw type)도 같이 정의된다. 그냥 List도 같이 만들어진다는 뜻이다.
그러면 왜 만들어지는 것이고 왜 쓰면 안되는걸까?

먼저 로 타입이 만들어지는 이유를 살펴보자. 간단하게 말하면 호환성 때문이다. 제네릭이 자바에 들어오기 전 오랜 기간 제네릭 없이 짠 코드가 널리 퍼져있었기 때문에 이를 호환하기 위해 없애지 않고 추가로 생성되게 한 것이다.

그러면 왜 쓰면 안되는걸까? 아래의 예시를 살펴보자.

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

위의 코드는 따라하지 말아야한다. stamps 인스턴스만 받는 Collection을 생성해놨다. 물론 stamps 인스턴스만을 받는 다는걸 확인하려면 주석을 확인해야 한다. 만약 이 코드를 사용하고 실수로 다른 클래스의 인스턴스를 넣어도 아무 오류 없이 들어가진다.
대신 컴파일러에서 경고메시지를 보여준다.
만약 아래와 같이 Stamp 클래스가 아닌 Coin 클래스를 넣는다면

stamps.add(new Coin(...)); // "unchecked call" 경고를 내뱉는다.

컴파일시 경고만 나올 뿐이고 넣었던 동전을 꺼내려고 해야 오류(ClassCastException : 형변환 오류)가 나오는데.

for(Interator i = stamps.iterator(); i.hasNext(); ){
	Stamp stamp = (Stamp) i.next(); // ClassCastException 에러
    stamp.cancel();
}

오류란, 컴파일할 때 발견하는게 가장 좋다. 위의 오류는 런타임중에 발생하기 때문에 원인을 찾기 위해 모든 코드를 살펴봐야 할 수도 있게 된다.
이렇듯 그냥 raw 타입을 쓰게 되면 모든 인스턴스를 받을 수 있게 되고 실수를 하게되면 찾기 어렵다. 하지만 아래와 같이 제네릭을 쓴다면

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

컴파일러에 Stamp 인스턴스만 넣어야 한다고 명시하기 때문에 다른 인스턴스가 들어가려 하면 컴파일 과정에서 에러가 발생하여 조기 수정이 가능해진다.

만약 타입 매개변수가 무엇인지 신경 쓰고 싶지 않다면 Set<?>와 같이 비한정적 와일드카드 타입 : ? 을 사용하자. ?를 사용하면 어떤 타입이든 담을 수 있게 된다.

좋은 웹페이지 즐겨찾기