|

자바 varargs는 언제 편하고 언제 위험할까: 가변 인자 사용 기준

자바 varargs 가변 인자 사용 기준 대표 이미지
varargs는 호출하는 쪽의 코드를 편하게 만들지만, API 경계에서는 모호성을 만들 수 있습니다.

자바 varargs는 인자 개수가 매번 달라지는 메서드를 더 편하게 호출하게 해 주는 문법입니다. `String… values`처럼 쓰면 호출하는 쪽에서는 여러 값을 쉼표로 넘길 수 있습니다.

핵심은 varargs가 편한 호출 문법을 제공하지만 메서드 내부에서는 배열처럼 다뤄진다는 점입니다. 이 글은 Java 공식 튜토리얼과 JLS 기준으로 언제 편하고 언제 조심해야 하는지 정리합니다.

자바 varargs 사용 기준 요약 카드
varargs는 여러 인자를 배열처럼 받을 수 있게 하지만, 마지막 매개변수에만 사용할 수 있습니다.

자바 varargs를 먼저 한 줄로 정리하면

varargs는 메서드가 같은 타입의 인자를 0개 이상 받을 수 있게 하는 문법입니다. 선언할 때는 `…`을 쓰고, 메서드 내부에서는 배열처럼 다룹니다.

static void printAll(String... values) {
    for (String value : values) {
        System.out.println(value);
    }
}

printAll("A", "B", "C");

호출하는 쪽에서는 인자를 여러 개 넘기는 것처럼 보이지만, 메서드 안의 `values`는 `String[]`처럼 사용할 수 있습니다.

varargs는 마지막 매개변수에만 쓸 수 있다

가변 인자는 어디까지가 varargs에 들어가는 값인지 구분해야 하므로 매개변수 목록의 마지막에만 둘 수 있습니다.

static void log(String level, String... messages) {
    for (String message : messages) {
        System.out.println("[" + level + "] " + message);
    }
}

배열을 직접 넘길 수도 있다

varargs는 내부적으로 배열처럼 다뤄지므로, 호출할 때 이미 가진 배열을 넘길 수도 있습니다.

String[] names = {"kim", "lee"};
printAll(names);

이 특성 때문에 varargs는 편하지만, 배열을 받는 API와 거의 같은 경계에 있다는 점을 기억해야 합니다.

언제 편할까

  • 로그 메시지처럼 인자 개수가 자연스럽게 달라질 때
  • 테스트 helper에서 입력값을 간단히 나열하고 싶을 때
  • 문자열 join, validation rule 목록처럼 같은 종류의 값을 여러 개 받을 때
  • 호출부의 가독성이 배열 생성보다 중요할 때

오버로딩과 만나면 헷갈릴 수 있다

varargs 메서드를 오버로딩하면 컴파일러가 어떤 메서드를 골라야 할지 애매해지는 상황이 생길 수 있습니다. 특히 고정 인자 메서드와 가변 인자 메서드가 비슷하면 호출부가 읽기 어려워집니다.

static void send(String value) {}
static void send(String... values) {}

send("hello");  // 읽는 사람이 어떤 의도인지 헷갈릴 수 있음

컴파일이 되더라도 API 사용자 입장에서 의미가 모호하면 좋은 설계라고 보기 어렵습니다.

generic varargs 경고는 왜 나올까

generic과 varargs를 함께 쓰면 non-reifiable type과 배열이 만나는 지점에서 경고가 생길 수 있습니다. 단순 입문 코드에서는 자주 마주치지 않지만, 라이브러리 API를 만들 때는 가볍게 넘기면 안 됩니다.

@SafeVarargs
static <T> void printLists(List<T>... lists) {
    for (List<T> list : lists) {
        System.out.println(list);
    }
}

`@SafeVarargs`는 정말 안전한 구현일 때만 붙여야 합니다. 경고를 숨기기 위한 장식으로 쓰면 나중에 타입 안정성 문제를 놓칠 수 있습니다.

실무 체크리스트

  1. 인자들이 모두 같은 의미의 반복 값인지 확인한다
  2. 인자가 0개일 때 동작이 자연스러운지 정한다
  3. 배열을 받는 메서드가 더 명확한지 비교한다
  4. 오버로딩으로 호출 의미가 흐려지지 않는지 본다
  5. generic varargs 경고를 무시하지 않는다

정리

자바 varargs는 호출부를 간단하게 만드는 좋은 문법입니다. 하지만 API 경계에서는 오버로딩, 배열과의 관계, generic 경고까지 함께 봐야 안전하게 쓸 수 있습니다.

Java 문법 흐름은 자바 enum은 상수 모음보다 더 강하다, 자바 람다에서 effectively final은 왜 필요할까, 자바 제네릭 와일드카드 extends super 차이와 함께 보면 좋습니다. 외부 기준은 Oracle Java Tutorial – Arbitrary Number of Arguments, Java Language Specification 8.4.1 – Formal Parameters, Oracle Java Tutorial – Non-Reifiable Varargs Type를 확인했습니다.

함께보면 좋은 글