본문 바로가기
Baeldung번역&공부/Java-basic

Varargs란(Varargs in Java)

by ms727 2025. 2. 8.

원본 글: https://www.baeldung.com/java-varargs

Java5에서 도입된 Varargs가변 인자를 의미하는데, 이는 하나의 메서드가 매개변수로 여러 개의 값을 받을 수 있게 해주는 기능입니다.

이 글에서는 어떻게 사용할 수 있는지 학습합니다.

 

1. Before Varargs

Java5 이전에는 임의 갯수를 가지고 있는 인자 값을 넘기려면 배열형태로 넘기거나 N개의 함수를 오버본 글: https://www.baeldung.com/java-varargs

 

Java5에서 도입된 Varargs는 가변 인자를 의미하는데, 이는 하나의 메서드가 매개변수로 여러 개의 값을 받을 수 있게 해주는 기능입니다.

 

이 글에서는 어떻게 사용할 수 있는지 학습합니다.

 

 

 

1. Before Varargs

Java5 이전에는 임의 갯수를 가지고 있는 인자 값을 넘기려면 배열형태로 넘기거나 N개의 함수를 오버로딩 하여 사용했습니다.

 

public String format() { ... }

public String format(String value) { ... }

public String format(String val1, String val2) { ... }

2. Use of Varargs

Varargs는 내부 구현이 배열로 되어있어서 위와같은 불필요한 코드작성을 안할 수 있게 도와줍니다.

public String formatWithVarArgs(String... values) {
    // ...
}

 

이런식으로 구성할 수 있습니다.

formatWithVarArgs();

formatWithVarArgs("a", "b", "c", "d");

호출은 이런식으로 호출할 수 있습니다.

 

앞서 말했듯이 varargs는 배열로 구성되어있기에 일반 배열처럼 조작해줘야합니다.

 

3. Rules

varargs를 제대로 사용하기위해서는 몇 가지 규칙들을 지켜줘야합니다.

- 각 함수는 하나의 varargs파라미터만 가질 수 있습니다.

- varargs 인수는 반드시 마지막에 선언되어야합니다.

 

4. Heap Pollution

varargs를 사용하면 Heap오염이라는 것을 발생시킬 수 있습니다. 다음과 같은 예제를 확인해봅니다.

 

    @Test
    public void heap_pollution_test() {
        //String one = firstOfFirst(Arrays.asList("one", "two"), Collections.emptyList());

        Assertions.assertThrows(ClassCastException.class, () -> {firstOfFirst(Arrays.asList("one", "two"), Collections.emptyList());});
        //기대하던 결과
        //Assertions.assertEquals("one", one);
    }
    
    public static String firstOfFirst(List<String>... strings) {
        List<Integer> ints = Collections.singletonList(42);
        Object[] objects = strings;
        objects[0] = ints; // Hepa pollution

        return strings[0].get(0); //ClassCast Exception
    }

이 코드는 예외를 발생시킵니다.

 

4.1 Safe Usage

varargs를 사용하면 Java 컴파일러는 함수에 주어진 파라미터를 기준으로 배열을 생성합니다.

만약 제네릭 타입으로 varargs를 사용하게 되면 Runtime Exception을 마주할 수 있습니다. 자바 컴파일러는 이런 문제를 미리 방지하기 위해 unsafe varargs usage라는 경고를 표시해줍니다. 

 

그렇기에 varargs를 안전하게 사용하려면 다음과 같은 방식을 따라야합니다.

- 암묵적으로 만들어진 배열에 대해서는 값을 저장하지 않습니다.

- 생성된 배열에 대한 참조가 함수를 벗어나지 않게 합니다.

 

만약 함수 자체가 안전하다고 판단된다면 @SafeVarargs 어노테이션을 통해서 경고문을 무시할 수 있습니다.

간단히 말하자면 varargs는 그냥 값 전달용으로만 사용하고 수정을 하는 등의 작업은 지양하는편이 좋습니다.

 

4.2 Escaping Varargs Reference

varargs를 안전하지 사용하지 않는 또 다른 예시를 봅니다.

static <T> T[] toArray(T... arguments) {
    return arguments;
}

 

얼핏보면 위 함수는 전혀 문제가 될 것이 없어 보입니다.

그러나 return 구문을 통해서 varargs를 사용한 배열을 전달하고 있으므로 2번째 규칙에 어긋납니다.

 

왜 위 코드가 위험한지 다음 함수를 통해서 확인합니다.

static <T> T[] returnAsIs(T a, T b) {
    return toArray(a, b);
}
String[] args = returnAsIs("One", "Two");

 

이 코드는 결국 ClassCastException을 발생시킵니다. returnAsIs()함수에서 어떤 동작이 일어나는지 확인해봅니다.

 

- toArray() 함수에서 a,b를 넘깁니다. 이때 자바는 배열을 생성하려고합니다.

- Object[]타입은 모든 유형을 저장할 수 있으므로 컴파일러는 이 배열을 생성합니다.

- toArray() 는 Object[]을 리턴합니다.

- 함수를 호출한 곳에서는 String[] 배열형태로 받고 있는데 Object[]형을 넘기기에 ClassCastException을 발생시킵니다.

 

5. 결론

Varargs를 사용하면 많은 보일러플레이트 코드를 제거할 수 있습니다.

그리고 autoboxing을 통하여 코드를 작성하는데 많은 도움을 줄 수 있습니다.