Heap Pollution
Java에서 제네릭은 컴파일 시점에 타입 안정성을 보장하여 런타임 오류를 줄이는 도구이다.
그렇지만, 잘못된 제네릭 사용은 Heap Pollution 문제를 일으킬 수 있다.
Heap Pollution이란?
컴파일 타임에는 문제가 없어 보이지만, 런타임 시점에서 타입 안정성이 무너져 예상치 못한 타입이 힙에 저장되는 현상을 의미한다.
특히 컴파일러가 타입 오류를 검출하지 못하기 때문에, 디버깅이 어려운 버그로 이어질 수 있다.
주로 다음의 경우에 문제가 발생한다.
- raw type 사용 - 제네릭 타입을 명시하지 않고 원시 타입을 사용하는 경우
- 가변인자와 제네릭의 조합 - 제네릭 타입의 가변인자를 사용하는 경우
Raw Type으로 인한 Heap Pollution
현재 list 변수의 타입을 지정할 때, List의 타입을 별도로 명시하지 않고 사용진행.
그렇기 때문에 중간에 String이 삽입이 되어도 컴파일 단계에서는 에러가 발생하지 않음.
하지만, 런타임 환경에서 Integer로 캐스팅을 시도할 때 ClassCastException이 발생한다.
제네릭 그리고 가변인자의 조합
제네릭과 가변인자는 배열 내부에서 Object[]로 타입이 소거됨.
그렇기에 컴파일러는 List<Integer>가 들어오는 것을 인지하지 못함.
하지만, 런타임 환경에서 잘못된 타입의 Collection이 들어오기 때문에 ClassCastException이 발생합니다.
Heap Pollution 예방 방법
Raw Type을 사용금지
제네릭 타입을 사용할 때는 항상 파라미터를 명시하자.
List 대신 List<Integer> 혹은 List<String>과 같이 구체적인 타입을 지정하거나, 컴파일러가 타입을 추론할 수 있도록 사용하자.
컴파일러의 경고를 확인하기
Java 컴파일러는 잠재적인 Heap Pollution 문제를 경고로 알려준다.
주로 이러한 문제의 경우 IntelliJ 사용시 밑줄로 표시가 되므로, 꼭 한번씩은 확인을 하자.
@SafeVarargs 사용 주의하기
@SafeVarargs를 메서드에 사용하면 위의 사진에서 보이는 IntelliJ에서의 밑줄이 제거된다.
@SafeVarargs 어노테이션의 경우 개발자가 직접 안전하다는 것을 보장하는 어노테이션이다. 이에 따라 컴파일러 경고를 억제해 주지만, 잘못 사용 할 경우 런타임 오류를 초래할 수 있다.
타입 캐스팅을 최소화하고 안전하게 수행하기
불가피하게 타입 캐스팅이 필요한 경우, instanceof 연산자를 사용해 객체의 실제 타입을 확인한 후 캐스팅을 수행할 것.