배열보다는 되도록이면 리스트를 사용하라
되도록이면 리스트를 사용하라.
리스트는 제네릭타입이 적용되어 있으므로 문제가 있는 코드는 컴파일조차 되지 않는다.
배열과 리스트는 비슷해보이지만 차이가 있다.
공변? 불공변?
배열은 공변이기 때문에 런타임시에 실패한다.
실제 타입이 무엇인지 선언된 타입만 보고는 판단할수 없기 때문이다.
리스트는 기본적으로는 불공변이기 때문에 '호환되지 않는 타입'이라며 컴파일 타임에 실패한다.
타입 안정성을 생각하면 리스트를 사용하는 것이 현명하다.
배열은 런타임에도 자신이 담기로 한 원소의 타입을 가지고 있다.
제네릭은 런타임에는 제거되기 때문에 컴파일 타임에 타입 안정성을 체크한다.
때문에, 캐스팅 꼼수를 이용한다면 배열과 마찬가지로 런타임에 에러가 발생할수도 있다.
왜 타입 정보가 런타임에는 소거되는가?
제네릭이 만들어진 취지 > 컬렉션의 타입 안정성을 위해서 > 타입 안정성은 컴파일 타임에 검사가 가능함 > 런타임에는 필요 없음
+ 자바 6이전 제네릭이 없던 시절의 레거시 코드와 호환시키기 위해서...
타입정보가 소거되어버리는 제네릭은 그래서 배열과 함께 사용하지 못한다.
new List<E>[] // E 가 런타임에 소거되어버리므로 허용하지 않음,
// 배열은 실체화 되어 런타임에도 타입을 가지고 있어야 하기 때문
new List<String>[] // 마찬가지로 String 이라는 타입정보가 소거되어버림,
// 그렇담 Object를 가진 List[] 로 동작하면 되는거아님? > 제네릭의 취지, 타입안정성을 위해서 막아둠
new E[] // E 가 뭔데?
반대로 이것은 가능하다
List[] dd = new ArrayList[10] // 소거될 타입이 없는 raw 타입의 List 배열,
//취지는 어따 팔아먹음?
List<?>[] df = new ArrayList[10]
// 매개변수 타입에 의존하지 않는 제네릭 클래스의 메서드를 사용하기 위해 만든 비 한정적 와일드카드 ? 는 모든 타입의 상위이기 때문에 타입이 소거되지 않는다.
// 리턴타입으로 사용될때, 출력자체는 어떤 타입으로 튀어나올지 알수없기 때문에 ? 를 소거하지 않는 듯 하다.
// 반대로 입력타입으로 사용될때, ? 타입의 구현자가 있을수가 없기 때문에 null 만 입력의 대상이 된다.
배열과 제네릭의 타입 캐스팅은?

제네릭 타입을 가진 컬렉션 to 배열
이 경우 타입 캐스팅을 위해 강제로 (E[]) 를 넣게 되는데, 타입 안정성에 대한 경고가 발생한다.
하지만 메소드의 선언에는 타입 한정자 E가 붙어있으니 실제로는 문제가 없다.

E 타입 배열 to 제네릭 타입을 가진 컬렉션
속도가 중요한 것이 아니라면 배열보다는 컬렉션을 사용하도록 하자.
쓸데없이 뻘 캐스팅 하는게 아니면 컴파일 타임에 타입 안정성을 지켜주므로 안전하다.
item 28에서 이야기한 이유 뿐만 아니라
컬렉션 프레임워크에는 컬렉션을 다루는데 도움이 되는 메서드도 많이 제공하고 있기 때문에
퍼포먼스가 중요하다거나, 요소를 직접 핸들링 해야하는 이유가 있지 않는 한은 그냥 컬렉션을 사용하자.
타입 소거와 실체화, 실체화 불가 타입은 약간 어렵다 느껴질수 있으나,
배열은 런타임에도 타입을 확인하기 때문에 제네릭과 어울리지 못한다.
이걸 허용한다면 List<String>[] 은 런타임에 List[]가 될테고, 이는 곧 Object[]와 같기 때문이다.
라고 이해했는데... 이미 List[]를 허용하네?
타입 정보를 체크하지 못하므로 허용하지 않는다, 를 그냥 raw타입으로 쓰면 된다. 라고 오해하기에 충분한거같은데..
아무튼 제네릭을 썼을때 에러메시지가 참.. 사람이 알아먹으라고 쓴 메시지가 맞나 싶다.
그리고, 타입 소거에 대해서 설명할때는 뭔가 대단한 메커니즘인것처럼 소개하는데,
결국 그냥 하위 버전 호환성을 위해 타입정보를 없애버린걸 왜 자랑스럽게 써둔건지 이해가 불가능하다.
실제로 런타임에 타입정보를 가지고있는 c#을 쓰다가 다시 자바로 넘어온 본인으로서는 어처구니가 없다.
책에서는 고의로 설명을 하지 않은 것인지 모르겠지만,
런타임에는 제네릭을 사용한 클래스의 구체적인 타입을 확인할수 없는 문제가 있다.
예를들면 List<T> 와 List<String> 은 런타임에는 List 가 되어버리기 때문에
런타임에서의 상세한 타입비교가 어렵다는 문제가 있다.(둘은 런타임에선 같은 타입이다)
아마 스프링의 resttemplate을 이용한 api 호출을 해본 사람은 이해할수 있을것이다.
이런 폭탄을 숨겨두고 타입 이레이져라고 이름까지 붙이고 자랑스러워하는 모습이 좀...
해결 방법이 있긴한데 본인은 약간 궁색한 방법이라는 생각이 든다.
상세한 내용은 https://sungminhong.github.io/spring/superTypeToken/ 를 참고하자.