[Effective Java] Item26 - 로타입은 사용하지 말라

지구🌍·2023년 3월 4일
0

Effective Java 공부

목록 보기
7/12
post-thumbnail

제네릭이란?

💡 제네릭(Generic) : 클래스 내부에서 지정하는 것이 아닌 외부에서 사용자에 의해 지정되는 것을 의미한다. 한마디로 특정(Specific) 타입을 미리 지정해주는 것이 아닌 필요에 의해 지정할 수 있도록 하는 일반(Generic) 타입이라는 뜻

제네리은 java5부터 추가 되었다.
이전에는 컬렉션에서 객체를 읽어서 캐스트 해야함 -> 이 때 런타입 캐스트 에러가 발생할 위험이 있다.

제네릭의 장점

  1. 제네릭을 사용하면 잘못된 타입이 들어올 수 있는 것을 컴파일 단계에서 방지할 수 있다.
  2. 클래스 외부에서 타입을 지정해주기 때문에 타입을 체크하고 변환해줄 필요가 없다. 즉, 관리하기가 편하다.
  3. 비슷한 기능을 지원하는 경우 코드의 재사용성이 높다.

제네릭 관련 용어

  • 제네릭 클래스(인터페이스) : 타입 매개변수(type parameter)가 선언에 쓰이는 클래스(인터페이스)
  • 제네릭 타입 : 제네릭 클래스와 제네릭 인터페이스를 통틀어 이르는 말 Example<T>
  • 매개변수화 타입 : 각각의 제네릭 타입은 parameterizedType을 선언함 Example<String>
  • 타입 매개 변수(Type parameter) : 제네릭 선언에 사용된 매개변수 <T>
  • formalType : Example<E>
  • actualType : Example<String>
  • 로타입(raw type) : 제네릭 타입에서 타입 매개변수를 전혀 사용하지 않았을 때, Example 로타입은 제네릭 전 후 코드의 호환을 위한 것이며, 동작하지만 좋은 예는 아님!

왜 로타입을 사용하면 안될까?

  • 컴파일 시점에 에러를 잡을 수 없다!

로타입 예시

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class RawType {

    public static void main(String[] args) {
        List onlyString = new ArrayList();
        onlyString.add("문자열1");
        onlyString.add("문자열2");
        onlyString.add(13579);

        for (Iterator i = onlyString.iterator(); i.hasNext(); ) {
            String s = (String) i.next(); // ClassCastException 을 던진다.
        }
    }
}

실제로 값을 가져와서 캐스팅을 하는 시점에 오류가 발생하기 때문에, 컴파일러는 ClassCastException을 던진다.
컴파일 전엔 아무런 에러가 발생하지 않는다!!

제네릭 예시

import java.util.ArrayList;
import java.util.List;

public class GernericType {

    public static void main(String[] args) {
        List<String> onlyString2 = new ArrayList<String>();
        onlyString2.add("string1");
        onlyString2.add("string2");
        onlyString2.add(13579);
    }
}

컴파일 전 부터 에러가 난다!

로타입을 사용을 절대로 하지 말아야하는 이유는 하위버전과의 호환성 때문이다.!!

비한정적 와일드 카드 타입?

컬렉션의 타입 파라미터를 모르거나 어떤 원소 타입이던 넣고 사용하고 싶다면 비한정적 와일드 카드 타입 을 사용해라!

<E> -> <?>
null을 제외한 그 어떤 타입의 인스턴스도 넣을 수 없다. 즉, 컬렉션의 타입 불변식을 훼손하지 못하도록 아예 막아버림
그래서 로타입보다 훨씬 안전!

이 제약에서 벗어나고 싶으면 ? extends 클래스 와 같이 한정적 와일드 카드 타입을 이용해 어떤 클래스의 하위 클래스를 받을 것인지 명시하면 된다.

로타입을 사용할 수 밖에 없는 경우

  1. class 리터럴을 사용할 때
  • 자바 명세서는 class 리터럴에 매개변수화 타입을 사용하지 못하게 하였다. (배열과 기본 타입 허용)
  • List.class, String[].class, int.class는 허용하고, List<String>.classList<?>.class는 허용하지 않는다.
  1. instanceof 연산자를 사용할 때
  • 런타임에는 제네릭 정보가 지워져서 instanceof 연산자는 비 한정적 와일드 카드 타입 이외의 매개변수화 타입에는 적용할 수 없다.
  • 로타입 비한정적 와일드 카드 타입의 instanceof는 완전 똑같이 동작한다.

🎈귀중한 참고자료🎈
참고자료1
참고자료2

profile
일취월장 하며 성장! 중! 공부한 것을 기록하자(^∀^●)ノシ

0개의 댓글