[Effective Java] - 5장 아이템 26. 로 타입은 사용하지 말라

yeom yaloo·2023년 12월 11일
0

Effective Java

목록 보기
14/20

제네릭

[아이템 26. 로(raw) 타입은 사용하지 말라]

  • 제네릭이 무엇인지를 알아보고 로타입이 무엇인지를 알아보자

[핵심 정리]

  • 제네릭을 도입하는 도중 이를 잘 적응시키기 위해서 로타입을 만들었다.
  • 그러나 로 타입은 리터럴을 사용하는 경우가 아니라면 사용하지 말자

[용어 정리]

1. 클래스와 인터페이스 선언에 타입 매개변수 사용

  • 클래스나 인터페이스 선언 시에 타입 매개변수를 사용하면 제네릭 클래스, 제네릭 인터페이스가 된다.

1-1. 클래스 선언에 타입 매개변수 사용한 경우

public class ClassName<T>{ ... }

1-2. 인터페이스 선언에 타입 매개변수를 사용한 경우

public interface InterfaceName<T>{ ... }

2. 타입 파라미터를 가지고 인터페이스, 클래스를 선언하는 이유

  • 어떤 종류의 객체든지 저장할 수 있기 때문이다.
  • 또한 타입 변환의 문제를 막을 수 있기 때문이다.

[로 타입 (raw type)]

  • 제네릭 타입을 하나 정의하면 그에 딸린 로타입도 함께 정의된다.

1. 로 타입이란?

  • 제네릭 타입에서 타입 매개변수를 전혀 사용하지 않은 경우 로 타입이라 한다.
  • List:는 로타입에 해당한다.
  • List<String>:은 제네릭 타입에 해당한다.
  • 로 타입은 제네릭 정보가 전부 지워진 것처럼 동작한다.
  • 로 타입은 제네릭이 도입되기 전의 코드와 도입된 후의 코드가 호환이 잘 되게 하기 위한 방법 중 하나다.

2. 로 타입의 예시 코드


private final Collection stamps =...;

stamps.add(new Coin(...)); // unchecked call 경고를 뱉는다.
  • 해당 코드는 컴파일러가 모호한 경고 메시지를 보여주기만 할 뿐 객체를 꺼내서 사용하지 않는한 문제가 되지 않는다.
  • 그러나 객체를 꺼내 사용하게 된다면 컴파일러 측에서 잡아낼 수 있던 에러도 런타임에 문제를 겪는 코드가 될수 있기 때문에 가능하면 컴파일시에 해당 오류를 잡아내는 것이 좋다.

3. 로 타입 말고 매개변수화된 컬렉션 타입 사용 코드

private final Collection<Stamp> stamps =...;
  • 해당 작업을 진행함으로서 해당 컬렉션에는 Stamp 객체만 넣어야 함을 컴파일러가 인지하게 된다.
  • 따라서 아무 경고 없이 컴파일되는 경우라면 의도대로 동작한 것임을 보장하게 되는 것이다.
  • 타입 매개변수를 사용하여 정의한 것에 다른 타입의 데이터를 넣으려 하면 컴파일 오류가 발생한다.

4. 왜 로 타입을 막아두지 않았을까?

  • 로 타입을 사용하지 않아야 한다면서 왜 로 타입 사용을 막아두지 않았을까?
  • 자바가 제네릭을 받아들이기까지 10년이 걸렸는데 기존 코드를 수용하면서 제네릭 코드와도 함께 동작할 수 있게 해야 했기 때문이다.
  • 마이그레이션 호환성을 위해서 로 타입을 지원하고 제네릭 구현에는 소거 방식을 사용하기도 했다.

5. List<Object> 와 로타입의 차이점

  • List<Object>의 경우엔 임의의 객체를 모두 허용하는 매개변수화 타입이다.
  • 이때 해당 List<Object>의 경우엔 모든 타입을 허용한다고 컴파일러에게 알려주는 반면 로 타입의 경우엔 아예 발을 뺀 경우이기 때문에 List<Object>는 사용이 가능하다.

6. 그러나 List<Object>는 List를 넘겨 받는 메서드에 사용할 수 없다.

  • 제네릭의 하위 타입 규칙 때문인데, List<String>은 List의 하위 타입이지만, List<Object>의 경우엔 List의 하위 타입이 아니기 때문이다.

7. 비한정 와일드 카드 타입

  • 실제 매개변수가 무엇인지 신경 쓰고 싶지 않다면 물음표(?)를 사용하자.
  • Set<E>의 비한정 와일드 카드 타입은 Set<?>이다.
  • 이 비한정 와일드 카드 타입은 어떤 타입이라도 담을 수 있는 가장 범용적인 매개변수화 타입이다.

7-1. Set 로 타입과 Set<?>의 차이점?

  • 로타입은 안전하지 않고 비한정 와일드 카드 타입은 안전하다.

[로타입을 사용해야 할 때]

1. class 리터럴에는 로 타입을 사용해야 한다.

  • 자바 명세는 class 리터럴에 매개변수화 타입을 사용하지 못하게 되어 있다.
  • 배열과 기본 타입은 허용한다.

2. instanceof 연산자에는 로 타입을 사용해야 한다.

  • 런타임시에는 제네릭 정보가 지워지기 때문에 instanceof 연산자는 비한정적 와일드카드 타입 이외의 매개변수화 타입에는 적용할 수 없다.
  • 로 타입이든 비한정적 와일드카드 타입이든 instanceof에서는 완전히 똑같이 동작한다. 그래서 List<매개변수화타입>을 작성해서 코드를 써내려가는 건 코드를 길고 지저분하게 만드는 일이라 그냥 로 타입을 사용하는게 낫다.
profile
즐겁고 괴로운 개발😎

0개의 댓글