Study/java

[Java] 자바의 가변 인자(Varargs)와 @SafeVarargs

 

가변인자란?

자바의 가변인자는 메서드의 파라미터 개수를 유동적으로 관리할 수 있게 해주는 기능입니다.

이를 통해 개발자는 특정 메서드에 다양한 수의 인자를 전달할 수 있으며, 이는 동일한 기능의 메서드를 여러 개 정의하지 않고도 다양한 인자 조합을 처리할 수 있게 됩니다.

 

가변인자 예제

public static void main(String[] args) {
    // 가변 인자를 사용하여 3개의 정수를 전달합니다.
    System.out.println("sum(1, 2, 3) = " + sum(1, 2, 3));

    // 가변 인자를 사용하여 4개의 정수를 전달합니다.
    System.out.println("sum(1, 2, 3, 4) = " + sum(1, 2, 3, 4));

    // 가변 인자를 사용하여 5개의 정수를 전달합니다.
    System.out.println("sum(1, 2, 3, 4, 5) = " + sum(1, 2, 3, 4, 5));
}

// 가변 인자를 사용하여 정수들의 합을 계산합니다.
public static int sum(int... numbers) {
    int sum = 0;
    for (int number : numbers) {
        sum += number;
    }
    return sum;
}

자바 가변인자 적용 예제
자바 가변인자 적용 예제

위의 코드에서 메서드는 0개 이상의 int 값을 파라미터로 받을 수 있으며, 이는 내부적으로 배열로 처리됩니다.

 

가변인자 메서드 타입 안전성 문제

다음과 같은 경우에 가변인자의 타입 안전성에 문제가 생깁니다.

public static <T> T[] unsafe(T... elements) {
    return elements;
}

public static <T> T[] broken(T seed) {
    T[] plant = unsafe(seed, seed, seed);
    return plant;
}

public static void plant() {
    String[] plants = broken("seed");
}

 

1. unsafe 메서드

unsafe 메서드는 제네릭 가변인자 배열을 반환하고 있습니다.

가변인자 메서드에서는 타입 안전성이 보장되지 않을 수 있기 때문에, 배열을 그대로 반환하는 것은 매우 위험합니다.

가변인자 배열은 내부적으로 Object[] 배열로 변환되므로, 호출 시 타입 안정성이 깨질 가능성이 높습니다.

 

2. broken 메서드

broken 메서드는 unsafe 메서드를 호출하여 배열을 반환합니다.

unsafe(seed, seed, seed)를 통해 생성된 배열은 실제로 Object[] 타입입니다.

따라서 T[]로 반환한다고 해도 컴파일러는 Object[]를 T[]로 인식하지 못해 타입 안정성을 보장하지 못합니다.

 

3. plant 메서드

plant 메서드는 broken 메서드를 호출하면서 String 타입의 배열을 기대하지만, 실제로는 Object[] 배열을 반환받기 때문에 ClassCastException이 발생합니다.

Exception in thread "main" java.lang.ClassCastException: class [Ljava.lang.Object; cannot be cast to class [Ljava.lang.String; ([Ljava.lang.Object; and [Ljava.lang.String; are in module java.base of loader 'bootstrap')

 

@SafeVarargs란?

@SafeVarargs는 자바에서 가변인자를 안전하게 사용할 수 있도록 돕는 어노테이션입니다.

주로 제네릭 가변인자 메서드에서 경고를 억제하기 위해 사용되며, 7 버전에서 도입되었습니다.

이 어노테이션을 통해 제네릭 가변인자 사용 시 발생할 수 있는 타입 안전성 경고를 방지할 수 있습니다.

 

가변인자 메서드는 배열을 사용하기 때문에, 제네릭 가변인자는 타입 소거(Type Erasure) 과정에서 타입 안전성이 완벽하게 보장되지 않아 컴파일러가 경고를 발생시킬 수 있습니다.

이러한 경고를 억제하는 것이 @SafeVarargs의 역할입니다.

 

@SafeVarargs 사용 시 주의사항

  • @SafeVarargs는 타입 안전한 가변인자 메서드에만 적용해야 합니다.
  • 제네릭 가변인자를 반환하는 경우, 특히 배열을 그대로 반환하는 방식은 위험할 수 있으므로 지양해야 합니다.
  • 안전한 메서드를 작성하려면 타입 캐스팅 없이도 안전하게 작동하는 방법을 사용하는 것이 좋으며, 가능하다면 배열 대신 리스트나 컬렉션을 사용하는 것이 안전성을 높이는 방법입니다.

 

@SafeVarargs는 컴파일러 경고를 억제해주지만, 내부적으로 타입 안전성을 보장하지 못할 경우 런타임에 예외가 발생할 수 있으므로 주의가 필요합니다.

 

 

참고

https://www.baeldung.com/java-safevarargs