IT/Programming / / 2023. 4. 27. 09:27

<Effective Java> RULE 25 배열대신 리스트를 써라

반응형

 

배열과 제네릭 자료형의 두가지 차이점

1. 배열은 공변 자료형이다.(covariant)

· Sub가 Super의 하위 자료형이라면 Sub[]는 Super[]의 하위 자료형이다.

· 제네릭은 불변 자료형이기 때문에 List<Type1>과 List<Type2>는 상위나 하위 자료형이 아니다.

· 배열을 쓰면 실행 시 알 수 있으나, 리스트를 쓰면 컴파일 시 알 수 있다.

// 런타임 에러
Object[] objectArray = new Long[1];
objectArray[0] = "dont fit in"; // ArrayStoreException발생

// 컴파일 에러
List<Ojbect> ol = new ArrayList<Long>(); //자료형 불일치
ol.add("dont fit in");
 

2. 배열은 실체화 되는 자료형이다.

· 배열의 자료형은 실행시간에 결정된다.

· 반면 제네릭 자료형은 삭제를 통해 구현된다.

 

위와같은 차이점 때문에 배열과 제네릭은 섞어 쓰기 어렵다.

· 제네릭 자료형이나 형인자 자료형, 또는 형인자의 배열을 생성하는 것은 문법적으로 허용되지 않는다.

* 제네릭 배열 생성은 형 안전성 때문에 보장되지 않는다.

//제네릭 배열 생성이 허용되지 않는 이유
List<String>[] stringLists = new List<String>[1];       //1 - 정상동작된다면
List<Integer> intList = Arrays.asList(42);              //2 - Integer리스트 초기화
Object[] objects = stringLists;                         //3 - 배열은 공변이므로 동작
objects[0] = intList;                                   //4 - Object[0]에 대입
String s = stringLists[0].get(0);                       //5 - 배열안의 원소 꺼내는데 컴파일러는  
 

제네릭 배열 생성 오류에 대한 가장 좋은 해결책은 List<E>를 쓰는 것이다.

// 리스트를사용하는 제네릭 버전 reduce
static <E> E reduce(List<E> list, Function<E> f, 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;
}
 

결론

· 제네릭과 배열이 따르는 자료형 규칙은 서로 많이 다르다.

· 배열은 공변 자료형이자 실체화 가능 자료형이다.

· 제네릭은 불변 자료형이며 실행 시간에 형인자 정보는 삭제 된다. 따라서 배열은 컴파일 시간에 형 안전성을 보장하지 못하며, 제네릭은 그 반대다.

· 일반적으로 배열과 제네릭은 쉽게 혼용할 수 없다.

· 만일 배열과 제네릭을 뒤섞어 쓰다가 컴파일 오류가 생긴다면 배열을 리스트로 바꿔야 겠다는 생각을 해야한다.

 

반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유