-
Effective Java 아이템 32 (Generic, Varargs, Heap Pollution)Java, JVM 2021. 8. 23. 22:14
힙 오염이란?
힙 오염은 parameterized type의 변수가 자신과 다른 타입의 객체를 참조하는 경우에 발생한다.
(Parameterized type은 List<String>, Set<Integer> 같은 것을 의미한다.)
다음과 같은 상황을 들 수 있다.
static method heapPollution() { List<String> stringList = new ArrayList<>(); List<Integer> integerList = List.of(1); stringList = (List<String>) (Object) integerList; // 힙 오염 발생 String s = stringList.get(0); // ClassCastException }
List<String> 타입인 stringList가 List<Integer> 타입의 객체를 참조하게 되면서 힙 오염이 발생하였다. 이 코드는 컴파일은 되지만, 런타임에 마지막 줄에서 ClassCastException이 발생한다.
제네릭과 varargs를 함께 쓸 때 주의할 점
varargs는 메서드를 사용하는 쪽에서 몇 개의 인자든 마음대로 넘길 수 있게 해주는 기능이다. 그런데 varargs는 제네릭과 함께 사용했을 때 위험한 문제를 일으킬 수 있다. 다음은 책에 나오는 예시이다.
public class Varargs { static <T> T[] toArray(T... args) { // 제네릭과 함께 varargs 사용 return args; } static <T> T[] pickTwo(T a, T b, T c) { switch(ThreadLocalRandom.current().nextInt(3)) { case 0: return toArray(a, b); case 1: return toArray(a, c); case 2: return toArray(b, c); } throw new AssertionError(); } public static void main(String[] args) { // toArray에 전달된 인자에 접근하는 코드 String[] attributes = pickTwo("a", "b", "c"); } }
얼핏 보면 문제가 없어 보이지만 위 코드는 런타임에 ClassCastException을 발생시킨다. 런타임에 toArray의 리턴 타입은 Object[]인데, main에서 Object[]를 String[]로 형변환을 시도하기 때문이다. 설명하자면 다음과 같은 상황이다.
// no exception Object[] o = new String[10]; String[] s = (String[]) o; // ClassCastException -> 여기에 해당 Object[] o = new Object[10]; String[] s = (String[]) o;
실제로 힙 오염 발생할 수 있기 때문에 제네릭과 함께 varargs parameter을 사용하면 "Possible heap pollution..."이라는 경고가 출력된다. 만약 문제가 발생하지 않는 코드가 확실하다면 @SafeVarargs를 사용하여 이 경고를 숨길 수 있다. @SafeVarargs는 메소드 사용자에게 경고를 숨기는 역할을 하기 때문에 반드시 실제로 코드가 안전하다는 확신이 있을 때만 사용해야 한다. 다음은 책에 나오는 안전한 코드의 예시이다.
@SafeVarargs static <T> List<T> flatten(List<? extends T>... lists) { List<T> result = new ArrayList<>(); for (List<? extends T> list : lists) { result.addAll(list); } return result; }
(또는 클라이언트에서 아예 varargs를 사용하지 않고 List를 넘기도록 만드는 것도 한 가지 방법이라고 한다.)
출처: Effective Java, Third Edition
'Java, JVM' 카테고리의 다른 글
자바에서 날짜와 시간 다루기 (0) 2022.03.20