배열로 선언하든 제네릭으로 선언하든 가변인수로 선언하면 내부적으로 배열이 만들어진다. 문제는 배열은 공변이고 제네릭은 불공변이다. 제네릭은 컴파일시에 타입을 체크하지만 배열은 런타임에 타입을 체크한다. 이러한 불일치성과 제네릭으로 선언해도 내부적으로 배열로 생성되기 때문에 잠재적으로 힙오염이나 ClassCastException을 일으킬 수 있다.
varargs의 타입을 안전하게 사용하기 위해서 자바에서는 @SafeVarags 애너테이션을 제공해준다. 그러나 해당 어노테이션을 적용할 때는 @SupressWarnings와 마찬가지로 완전하게 안전할 때 사용해야 한다. 그런 경우를 살펴보자.
보통 참조되는 클래스나 배열의 경우 방어적 복사를 한다. 이런 경우 안전하게 사용가능하다.
@SafeVarargs
static <T> List<T> flatten(List<? extends T> ...lists) {
for (List<? extends T> list: lists) {
result.addAll(list);
}
return result;
}
외부에 노출시키지 않고 내부적으로만 사용하며 단순히 데이터만 활용하는 경우 안전하다.
재정의하는 메서드의 경우 문제가 생길 우려가 있다. 그렇기에 자바 8에서는 final 인스턴스 메서드와 정적 메서드에만 사용가능했다. 그러나 자바9 부터는 private 인스턴스 메서드에도 붙일 수 있기 때문에 조심해서 사용하도록 하자.
List.of는 가변인자를 받아서 ImmutableList를 만들어주는 좋은 정적 메서드이다. 이를 활용하면 비검사 경고나, 예외에 대해서 안전하게 사용할 수 있다.