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

신명철·2022년 2월 22일
0

Effective Java

목록 보기
24/80

로 타입

로 타입은 제네릭이 도입되기 이전 코드와의 호환성을 위해서 제공된다.
제네릭 타입에서 타입 매개변수를 전혀 사용하지 않을 때를 말한다.

e.g) List<E> -> List

문제점

로 타입에는 다른 타입의 매개변수가 컬렉션에 들어갈 때 컴파일 시점이 아닌 런타임 시점에 에러를 발견하는 문제가 있다.

private final Collection Stamps = ...;
Stamps.add(new Coin())  // 도장이 아니라 동전을 넣어버렸다

제네릭을 활용해 아래와 같이 타입 매개변수를 정의하면 엉뚱한 타입의 인스턴스를 넣는 걸 컴파일러가 막아줄 수 있다.

private final Collection<Stamp> Stamps = ...;
Stamps.add(new Coin())  // 오류 발생!!

로 타입을 쓰게 되면 제네릭이 안겨주는 안정성과 표현력을 모두 잃게 된다

List 와 List<Object>

만약 모든 타입을 받을 수 있는 컬렉션을 원한다면 List<Object> 처럼 임의 객체를 허용하는 매개변수화 타입을 선언하자.

List 는 제네릭 타입에서 완전히 발을 뺀 것이고 List<Object>는 모든 타입을 허용한다는 의미를 컴파일러에게 명확하게 전달한 것이다.

매개변수로 List를 받는 메소드에 List<String>은 전달할 수 있지만 List<Object>를 받는 메소드에는 전달할 수 없다. 이는 제네릭 하위타입 규칙 때문이다. List<String>은 List의 하위타입이지만 List<Object>의 하위타입은 아니다.

만약, 제네릭 타입을 쓰고 싶지만 매개변수 타입이 무엇인지 신경쓰고 싶지 않을 때는 ? 를 쓰자. 제네릭 타입인 Set<E>의 비한정적 와일드 카드 타입은 Set<?>이다.

로 타입을 사용하는 예

클래스 리터럴

class 리터럴에는 로 타입을 사용해야 한다. 자바 명세에서는 클래스 리터럴에 매개변수화 타입의 사용을 못하게 했다. 즉, List.class, String[].class, int.class 는 허용하지만 List<String>.class 와 같은 방식은 허용하지 않는다.

instanceof

런타임에는 제네릭 타입 정보가 지워지기 때문에 instanceof 연산자는 비한정적 와일드 카드 타입 이외 매개변수화 타입에는 적용할 수 없다. 그리고 로 타입이든 비한정적 매개변수 타입이든 instanceof는 동일하게 작용한다. 비한정적 와일카드 타입의 꺾쇠괄호와 물음표는 아무 역할 없이 코드만 지저분하게 하기 때문에 차라리 로 타입을 쓰는 편이 깔끔하다.

profile
내 머릿속 지우개

0개의 댓글