ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Effective Java] 아이템26: 로 타입(raw type)은 사용하지 말라
    Language/Java 2022. 7. 29. 16:29

     

    ✔️ 제네릭 타입과 로 타입

    클래스와 인터페이스 선언에 타입 매개변수가 쓰이면 제네릭 클래스 혹은 제네릭 인터페이스라고 하며, 두 가지를 통틀어 제네릭 타입(generic type)이라고 한다.

    로 타입(raw type)이란 타입 매개변수가 없는 제네릭 타입을 말한다. 예를 들어, List<E>의 로 타입은 List다.

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

     

    ✔️ 컬렉션의 로 타입

    컬렉션 로 타입을 사용할 경우, 엉뚱한 타입을 넣어도 오류 없이 컴파일되고 실행될 수 있다.
    이 경우, 형변환 시 ClassCastException을 던지게 된다.

     

    📍 컬렉션의 로 타입  → 좋지 않은 예!

    private final Collection stamps = ...;
    ...
    
    stamps.add(new Coin(...)); // 실수로 동전을 넣는다.
    ...
    
    for(Iterator i = stamps.iterator(); i.hasNext();) {
        Stamp stamp = (Stamp) i.next(); // ClassCastException을 던진다.
        stamp.cancel();
    }

     

     

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

    다음과 같이 선언하면, 컴파일러는 엉뚱한 타입의 인스턴스를 넣으려고 할 때 오류를 발생시킨다.

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

     

    '로 타입을 쓰면 제네릭이 안겨주는 안전성과 표현력을 모두 잃게된다'는 점을 기억하자!

     

     

    📍 매개변수화 타입 → 타입 안전성!

    List와 같은 로 타입은 사용해서는 안 되지만, List<Object>와 같은 임의 객체를 허용하는 매개변수화 타입은 괜찮다.
    매개변수화 타입은 컴파일러에게 모든 타입을 허용한다는 의사를 명확히 전달한 것이다.

     

     

    📍 비한정적 와일드카드 타입 → 타입 안전하며 유연!

    제네릭 타입을 쓰고 싶지만, 실제 타입 매개변수가 무엇인지 신경쓰고 싶지 않을 때는 비한정적 와일드 카드 타입을 사용하자.

    비한정적 와일드 카드는 물음표(?)를 사용하면 된다.
    예를 들어, Set<?>, Collection<?> 이런 식이다.

     

     

    ✔️ 예외

    class 리터럴에는 로 타입을 써야 한다.

    • 자바 명세는 class 리터럴에 매개변수화 타입을 사용하지 못하게 했다. (배열과 기본 타입은 허용한다.)
    • ex) List.class, String[].class, int.class (O)
            List<String>.class, List<?>.class   (X)

     

    instanceof 연산자는 로 타입을 써도 좋다.

    • instanceof 연산자는 로 타입이든 비한정적 와일드카드 타입이든 완전히 똑같이 동작한다.
    • 이때는 꺽쇠괄호와 물음표 없이 깔끔하게 로 타입을 쓰는 것이 좋다.
    if(o instanceof Set) { // 로 타입
        Set<?> s = (Set<?>) o;
        ...
    }

     

     

    ✔️ 용어 정리

    한글 용어 영문 용어 아이템
    매개변수화 타입 parameterized type List<String> 아이템 26
    실제 타입 매개변수 actual type parameter String 아이템 26
    제네릭 타입 generic type List<E> 아이템 26, 29
    정규 타입 매개변수 formal type parameter E 아이템 26
    비한정적 와일드카드 타입 unbounded wildcard type List<?> 아이템 26
    로 타입 raw type List 아이템 26
    한정적 타입 매개변수 bounded type parameter <E extends Number> 아이템 29
    재귀적 타입 한정 recursive type bound <T extends Comparable<T>> 아이템 30
    한정적 와일드카드 타입 bounded wildcard type List<? extends Number> 아이템 31
    제네릭 메서드 generic method static <E> List<E> as List(E[] a) 아이템 30
    타입 토큰 type token String.class 아이템 33

     

     

     

    핵심 정리

     

    • 로 타입을 사용하면 런타임에 예외가 발생할 수 있으니 사용하면 안 된다.
    • 로 타입은 제네릭이 도입되기 이전 코드와의 호환성을 위해 제공될 뿐이다.
    • 매개변수화 타입: Set<Object>, 어떤 타입의 객체도 저장할 수 있다.
      와일드카드 타입: Set<?>, 모종의 타입 객체만 저장할 수 있다.
      로 타입: Set
    • Set<Object>와 Set<?>는 안전하지만, Set은 안전하지 않다.

     

     

     

     

     

    728x90

    댓글

Designed by Tistory.