Java/이펙티브 자바

아이템28. 배열보다는 리스트를 사용하라

PHM 2023. 9. 23. 12:28

핵심 정리1 - 배열과 제네릭은 잘 어울리지 않는다.

- 배열은 공변(covariant), 제네릭은 불공변

- 배열은 실체화(reify) 되지만, 제네릭은 실체화 되지 않는다. (소거)

    ㆍ제네릭은 컴파일할 때 타입이 사라진다.

- new Generic<타입>[배열] 은 컴파일 할 수 없다.

- 제네릭 소거 : 원소의 타입은 컴파일 타임에만 검사하며 런타임에는 알 수 없다.

public static void main(String[] args) {
        // 공변 : 같이 변한다.
        Object[] anything = new String[10];
        anything[0] = 1;    // 잘못된 동작이지만 컴파일러가 잡지 못한다. - 런타임 에러

        // 불공변 : 같이 변하지 않는다.
        List<String> names = new ArrayList<>();
//        List<Object> objects = names; // 컴파일 에러.
}

 

핵심 정리2

- 배열기반은 범용적으로 사용하기 어렵다. - 타입 캐스팅을 써야함.

    ㆍ범용적으로  쓸 수 있는 클래스의 타입 형변환 문제 발생 -> 제네릭 사용

 

완벽 공략 - @SafeVarargs

: 생성자와 메서드의 제네릭 가변인자에 사용할 수 있는 애노테이션

 

- 제네릭 가변인자는 근본적으로 타입 안전하지 않다. (가변인자가 배열이니까, 제네릭 배열과 같은 문제)

- 가변 인자 (배열)의 내부 데이터가 오염될 가능성이 있다.

- @SafeVarargs를 사용하면 가변 인자에 대한 해당 오염에 대한 경고를 숨길 수 있다.

- 아이템 32. 제네릭과 가변인수를 함께 쓸 때는 신중하라.

public class SafeVaragsExample {

//    @SafeVarargs    // Not actually safe!
    static void notSafe(List<String>... stringLists) {  // List<String>[] 이 가능하지만 전달받은 객체가 오염이 될 수 있다.
        Object[] array = stringLists;       // List<String>... => List[], 그리고 배열은 공변이다.
        List<Integer> tmpList = List.of(42);
        array[0] = tmpList;                 // Semantically invalid, but compiles without warnings
        String s = stringLists[0].get(0);   // ClassCastException at runtime!
    }

//    @SafeVarargs
    static <T> void safe(T... values) {
        for (T value: values) {
            System.out.println(value);
        }
    }
}