복잡한뇌구조마냥

[JAVA] Effective Java - 로 타입(raw type)은 사용하지 말라 (26) 본문

BE/JAVA

[JAVA] Effective Java - 로 타입(raw type)은 사용하지 말라 (26)

지금해냥 2025. 8. 11. 16:16

1. 로 타입(Raw Type)이란?

  • 제네릭(Generic) 문법에서 타입 매개변수를 지정하지 않은 타입.
  • 예:
List list = new ArrayList(); // 로 타입
  • List<String>처럼 구체적인 매개변수화 타입을 쓰지 않은 상태.

2. 로 타입이 문제인 이유

  • 타입 안전성(Type Safety) 손실
    컴파일러가 타입 검증을 못 하므로 잘못된 타입이 들어가도 컴파일 단계에서 안 잡힘.
List list = new ArrayList();
list.add("문자열");
list.add(123); // 컴파일 OK, 런타임에서만 문제 발생 가능
  • 표현력 감소
    코드에서 어떤 타입을 의도했는지 알 수 없어 가독성↓, 유지보수성↓
  • 에러 검출 시점 지연
    문제를 런타임에서야 발견 → 디버깅 난이도 상승.
  • 컴파일러 최적화·도움 불가
    타입 추론이 안 되므로 IDE 경고, 자동완성, 리팩토링 지원 약화.

3. 안전한 대안

  • 1. 매개변수화 타입(Parameterized Type) 사용
List<String> list = new ArrayList<>();
list.add("문자열");
// list.add(123); // 컴파일 에러
  • 2. 비한정적 와일드카드(Unbounded Wildcard) 사용
    타입을 명확히 정하지 않더라도 모종의 타입이라는 건 보장.
List<?> list = new ArrayList<String>();
// list.add("문자열"); // 컴파일 에러: 안전성 확보
  • 3. Object 대신 와일드카드
    • <Object>: 어떤 타입의 객체도 넣을 수 있음
    • <?>: 읽기 전용(추가 불가, null 제외) → 더 안전

4. 로 타입을 써도 되는 예외

  • Class 리터럴
Class<String> stringClass = String.class; // OK
Class<?> anyClass = Object.class;         // OK
  • instanceof 연산자
    제네릭 타입 정보는 런타임에 지워지므로(타입 소거, type erasure)
    instanceof에는 로 타입을 써야 함.
if (obj instanceof List) { ... }

5. 자주 쓰이는 관련 용어

용어 의미 예시
매개변수화 타입
(Parameterized Type)
구체적인 실제 타입 매개변수를 지정한 제네릭 타입 List<String>
실제 타입 매개변수
(Actual Type Parameter)
매개변수화 타입에서 지정한 구체적인 타입 List<String>의 "String"
제네릭 타입
(Generic Type)
하나 이상의 타입 매개변수를 선언한 클래스/인터페이스 List<E>
정규 타입 매개변수
(Formal Type Parameter)
제네릭 타입 선언 시 사용되는 타입 변수 List<E>E
비한정적 와일드카드 타입
(Unbounded Wildcard Type)
어떤 타입이든 허용하지만 구체적인 타입 정보는 모름 List<?>
로 타입
(Raw Type)
타입 매개변수를 지정하지 않은 제네릭 타입 List list
한정적 타입 매개변수
(Bounded Type Parameter)
특정 타입이나 그 하위 타입으로 제한한 타입 매개변수 <E extends Number>
재귀적 타입 한정
(Recursive Type Bound)
자기 자신을 상속/구현한 타입 매개변수 <E extends Comparable<E>>
한정적 와일드카드 타입
(Bounded Wildcard Type)
와일드카드에 상한/하한 제한을 둔 타입 List<? extends Number>,
List<? super Integer>
제네릭 메서드
(Generic Method)
메서드 자체가 타입 매개변수를 선언하는 메서드 static <E> List<E> asList(E[] a),
<T> void print(T item)
타입 토큰
(Type Token)
런타임에 타입 정보를 전달하기 위한 클래스 리터럴 Class<String> clazz = String.class
 

6. 결론

로 타입은 타입 안정성과 표현력을 모두 잃게 만든다.
Class 리터럴이나 instanceof와 같은 특수한 상황이 아니라면,
항상 매개변수화 타입이나 와일드카드를 사용하자.

LIST