# 아이템53 가변인수는 신중히 사용하라

가변인수(vargs) 메서드는 명시한 타입의 인수를 0개 이상 받을 수 있다. 가변인수 메서드를 호출하면, 가장 먼저 인수의 개수와 길이가 같은 배열을 만들고 인수들을 이 배열에 저장하여 가변인수 메서드에 건네준다.

```java
static int min(int... args) {
    if (args.length == 0)
        throw new IllegalArgumentException("인수가 1개 이상 필요합니다.");
    int min = args[0];
    for (int i = 1; i < args.length; i++)
        if (args[i] < min)
            min = args[i];
        return min;
}
```

#### 이 방식에는 문제가 몇 개 있다.

* 가장 심각한 문제는 인수를 0개만 넣어 호출하면 (컴파일타임이 아닌) 런타임에 실패한다는 점이다.
* 코드도 지저분하다.

#### 개선해보자.

다음 코드처럼 매개변수를 2개 받도록 하면된다. 즉, 첫 번째로는 평범함 매개변수를 받고, 가변인수는 두 번째로 받으면 앞서의 문제가 말씀히 사라진다.

```java
static int min(int firstArg, int... remainingArgs) {
    int min = firstArg;
    for (int arg : remainingArgs)
        if (arg < min)
            min = arg;
    return min;
}
```

### 성능에 민감한 상항이라면 가변인수 사용은 고려해보자

가변인수 메서드는 호출될 때마다 배열을 새로 하나 할당하고 초기화한다. 가변인수의 유연성이 필요할 때 선택할 수 있는 멋진 패턴이 있다. 예를 들어 해당 메서드 호출의 95%가 인수를 3개 이하로 사용한다고 해보자. 그렇다면 다음처럼 인수가 0개인 것부터 4개인 것까지, 총 5개를 다중정의하자. 마지막 다중정의 메서드가 인수 4개 이상인 5%의 호출을 담당하는 것이다.

```java
public void foo() { }
public void foo(int a1) { }
public void foo(int a1, int a2) { }
public void foo(int a1, int a2, int a3) { }
public void foo(int a1, int a2, int a3, int... rest) { }
```

따라서 메서드 호출 중 단 5%만이 배열을 생성한다.

#### EnumSet의 정적 팩터리도 이 기법을 사용해 열거 타입 집합 생성 비용을 최소화한다.&#x20;

EnumSet은 비트 필드(아이템 36)를 대체하면서 성능까지 유지해야 하므로 아주 적절하게 활용한 예시라 할 수 있다.

#### 아이템 36 EnumSet 예

```java
import java.util.*;

// 코드 36-2 EnumSet - 비트 필드를 대체하는 현대적 기법 (224쪽)
public class Text {
    public enum Style {BOLD, ITALIC, UNDERLINE, STRIKETHROUGH}

    // 어떤 Set을 넘겨도 되나, EnumSet이 가장 좋다.
    public void applyStyles(Set<Style> styles) {
        System.out.printf("Applying styles %s to text%n",
                Objects.requireNonNull(styles));
    }

    // 사용 예
    public static void main(String[] args) {
        Text text = new Text();
        text.applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));
    }
}
```

### 정리

인수 개수가 일정하지 않은 메서드를 정의해야 한다면 가변인수가 반드시 필요하다. 메서드를 정의할 때 필수 매개변수는 가변인수 앞에 두고, 가변인수를 사용할 때는 성능 문제까지 고려하자


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://incheol-jung.gitbook.io/docs/study/effective-java/undefined-6/53.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
