Java에서 가변 인자(varargs) 기능은 배열 타입의 매개변수나 동일한 메서드의 오버로드된 버전을 만들지 않고도, 가변적인 개수의 인자를 받는 메서드를 손쉽게 작성할 수 있도록 도입되었습니다.
Java 9 이전 버전에서는 varargs 메서드를 제네릭(generics)과 함께 사용하면 경고 메시지가 표시되었습니다. 문제는 모든 메서드가 힙 오염(heap pollution)을 일으키는 것은 아님에도 불구하고, 컴파일러는 제네릭과 함께 사용되는 모든 varargs 메서드에 대해 경고를 출력한다는 점입니다. 이러한 불필요한 경고를 제거하기 위해 Java 9에서 @SafeVarargs 어노테이션이 도입되었습니다. 이 어노테이션을 추가하면 컴파일러가 더 이상 해당 경고를 출력하지 않습니다.
아래 명령어를 사용하여 코드를 컴파일할 수 있습니다.
javac -Xlint:unchecked SafeVarargsTest1.java
다음 예제에서는 컴파일러가 사용자에게 경고 메시지를 출력합니다.
예제 1: @SafeVarargs 미적용 시
import java.util.Arrays;
import java.util.List;
public class SafeVarargsTest1 {
public static void main(String args[]) {
SafeVarargsTest1 test = new SafeVarargsTest1();
test.varargsMethod(Arrays.asList("Adithya", "Jaidev"), Arrays.asList("Raja", "Chaitanya"));
}
private void varargsMethod(List<String>... list) {
for(List list1: list)
System.out.println(list1);
}
}출력 결과
SafeVarargsTest.java:7: warning: [unchecked] unchecked generic array creation for varargs parameter of type List[]
test.varargsMethod(Arrays.asList("Adithya", "Jaidev"), Arrays.asList("Raja", "Chaitanya"));
^
SafeVarargsTest.java:9: warning: [unchecked] Possible heap pollution from parameterized vararg type List
private void varargsMethod(List... list) {
^
2 warnings
[Adithya, Jaidev]
[Raja, Chaitanya]위 출력 결과에서 볼 수 있듯이, 코드는 정상적으로 실행되지만 컴파일 과정에서 두 개의 [unchecked] 경고가 발생합니다. 하나는 varargs 매개변수를 위한 제네릭 배열 생성과 관련된 경고이고, 다른 하나는 매개변수화된 varargs 타입으로 인한 잠재적 힙 오염 가능성에 대한 경고입니다.
다음 예제에서는 private 메서드 앞에 @SafeVarargs 어노테이션을 적용했습니다. 그 결과 어떠한 경고 메시지도 표시되지 않습니다.
예제 2: @SafeVarargs 적용 시
import java.util.Arrays;
import java.util.List;
public class SafeVarargsTest2 {
public static void main(String args[]) {
SafeVarargsTest2 test = new SafeVarargsTest2();
test.varargsMethod(Arrays.asList("Adithya", "Jaidev"), Arrays.asList("Raja", "Chaitanya"));
}
@SafeVarargs
private void varargsMethod(List<String>... list) {
for(List list1: list)
System.out.println(list1);
}
}출력 결과
[Adithya, Jaidev] [Raja, Chaitanya]
정리
@SafeVarargs 어노테이션은 개발자가 해당 varargs 메서드가 타입 안전성을 해치지 않는다는 것을 보장할 때 사용합니다. 이 어노테이션은 static 메서드, final 메서드, private 메서드(Java 9부터), 생성자에만 적용할 수 있습니다. Java 9부터는 private 메서드에도 사용 가능해져, 캡슐화된 헬퍼 메서드에서 제네릭 varargs를 더욱 유연하게 활용할 수 있게 되었습니다.