본문 바로가기
프로그래밍 놀이터/디자인 패턴, 리펙토링

[Effective Java] 배열보다는 List 를 사용하자.

by 돼지왕 왕돼지 2016. 11. 28.
반응형

 [Effective Java] 배열보다는 List 를 사용하자.


array, array list, compile error, covariant, Effective JAVA, Erasure, invariant, list, List Array, nonreifiable, relified, runtime error, subclass, sub[], superclass, super[], typ2, type1, unbound wild cards, [Effective Java] 배열보다는 List 를 사용하자., 간결함, 공변, 구체적, 규칙, 런타임, 런타임 에러, 배열, 배열 타입, 불변, 비구체화, 상호 운용성, 서브 클래스, 성능, 소거, 소거자, 슈퍼 서브, 슈퍼 클래스, 안전성, 요소 타입 정보 무시, 유연성, 제네릭, 제네릭 타입, 컬렉션 타입, 컴파일, 컴파일 에러, 타입 안전, 특별한 상황, 호환 운용 보장


-
배열은 두 가지 관점에서 제네릭 타입과 다르다.

1.
array는 공변(covariant).
Sub이 Super 의 서브 타입이라면, 배열 타입 Sub[] 은 Super[] 의 서브 타입이라는 의미.

제네릭은 불변(invariant).
Type1 와 Type2 가 있을 때, 이들의 관계는 모두 무시하고, List<Type1> 과 List<Type2> 는 서로 슈퍼도 서브도 아니다.

이 차이를 기반으로 제네릭이 유연성을 떨어뜨린다고 볼 수 있지만, array는 안전성을 보장하지 못한다.
배열을 사용하면 런타임 에러를 발생시키기 쉽고, List 를 사용하면 컴파일 에러를 마딱뜨리기 쉽다.
당연히 컴파일 시 에러를 발견하는 것이 최고다.


2.
array 는 구체적(relified).
배열은 자신의 요소 타입을 런타임 시에 알고 지키게 한다.

제네릭은 소거자(erasure).
컴파일 시에만 자신의 타입 제약을 지키게 하고, 런타임 시에는 자신의 요소 타입 정보를 무시(소거)한다. -> 호환 운용 보장.


이 차이로 배열과 제네릭은 잘 혼용되지 않는다.
따라서 new List<E>[], new List<String[]>, new E[] 와 같은 배열 생성식을 사용할 수 없다. ( 그 이유는 요래저래 따져보면 나온다. -> 책 참조 )
( unbound wild cards 타입 제외 )
컴파일 시 제네릭 배열 생성 에러가 발생한다.


-
컴파일 시보다 런타임 시에 더 적은 정보를 갖는 것을 비구체화(nonreifiable) 타입이라고 한다.


-
제네릭 배열 생성 에러가 생길 때 가장 좋은 해결책은 배열 타입인 E[] 보다는 컬렉션 타입인 List<E> 를 사용하는 것이다.
성능이나 코드의 간결함 관점에서 손해를 볼 수 있지만, 그대신 타입 안전과 상호 운용성이 더욱 좋아진다.


-
비구체화(non-reifiable)타입의 배열로 캐스팅하는 것은 특별한 상황에서만 고려되어야 한다.
제대로 코드를 작성하면 사실상 문제없이 돌아가긴 하지만, 우선은 위험 가능성은 언제든 있긴 있는 것이다.



Summary


배열과 제네릭은 전혀 다른 타입 규칙을 갖는다.
배열은 그 특성이 공변(covariant)이고, 구체적(reified)이다.
제네릭은 불변(invariant)이면서 런타임 시 타임 정보가 없어진다.
배열은 런타임 시 타입 안전이 제공되지만 컴파일 시 타입 안전은 제공되지 않는다.
제네릭은 반대로 런타임 시 타입 안전이 제공되지 않지만, 컴파일 시 타입 안전이 제공된다.
배열과 제네릭은 일반적으로 잘 섞어 쓰지 않는다.
만일 섞어 써야 하는 경우가 생기면 가급적 배열을 List 형태로 변환해서 써야 안전하다.





반응형

댓글