아이템 25. 배열 대신 리스트를 써라.

배열 대신 리스트를 써라.

배열과 리스트의 차이점

// 실행 중에 예외 발생
Object[] objectArray = new Long[1];
objectArray[0] = "I don't fit in"; // ArrayStoreException 예외 발생


// 하지만, 아래의 코드는 컴파일 되지 않음
List<Object> objectList = new ArrayList<Long>(); // 자료형 불일치로 컴파일 되지 않음
objectList.add("I don't fit in");

좀더 자세한 내용은 (Effective Java 2/E 162p~163p 참조)

interface Function<T>{
    T apply(T arg1, Targ2);
}

// reduce의 제네릭 버전, 컴파일 되지 않는다.
static <E> E reduce(List<E> list, Function<E>, E initVal){
    E[] snapshot = list.toArray(); // 내부적으로 리스트에 락을 건다.
    E result = initVal;
    for( E e : snapshot )
        result = f.apply(result, e);
    return result;
}

위 코드를 실행하면, 아래와 같은 에러 메시지가 발생한다.

Reduce.java:12: incompatible types
found : Object[], required: E[]
    E[] snapshot = list.toArray();
                        ^

cast문제로 생각되어 아래와 같이 고치면,

E[] snapshot = (E[])list.toArray();

위와 같이 코드를 수정하면, 오류는 사라지지만, 대신 아래와 같은 경고 메시지가 발생한다.

Reduce.java:12: warning: [unchecked] unchecked cast
found : Object[], required: E[]
    E[] snapshot = (E[])list.toArray();
                                ^

컴파일러가 전하려는 메시지는 실행 도중에 형 변환이 안전하게 이루어질지 검사 할수 없다는 뜻이다. 실행 시에 타입제거(Type Erasure)로 인해 E가 무슨 자료형이 될지 알수 없다.

안전한 형 변환 검증을 위해서 리스트를 사용하자, 아래의 코드는 실행 도중에 ClassCastException이 발생하지 않는다.

// 리스트를 사용하는 제네릭 버전
static <E> E reduce(List<E> list, Function<E>, E initVal){
    List<E> snapshot;
    synchronized(list){
        snapshot = new ArrayList<E>(list);
    }
    E result = initVal;
    for( E e : snapshot )
        result = f.apply(result, e);
    return result;
}

결론

제네릭과 배열이 따르는 자료형 규칙이 서로 많이 다르다. 만약 배열과 제네릭을 뒤섞어 쓰다가 컴파일 오류나 경고메시지를 만나게 되면 배열을 리스트로 바꾸자.

구분 Type 실체화(구체화) 형 안정성
배열 공변 자료형(covariant) 가능 Run time에 보장
제네릭 불변 자료형(invariant) 불가능 Compile time에 보장

E, List<E>, List<String>등과 같은 자료형은 구체화 불가능(non-reifiable)자료형으로 컴파일시에는 타입 정보를 알수 있으나 런타임 시에 타입제거(Type erasure)로 인해 타입의 모든 정보를 런타임시에 알수가 없다. 반대로, primitive, non-generic, raw 타입, 비한정 와일드 카드형 타입(<?>) 등은 구체화 가능 자료형(reifiable)이다.

참고 : https://docs.oracle.com/javase/tutorial/java/generics/nonReifiableVarargsType.html