Skip to content

Commit

Permalink
docs: 이펙티브 자바 item 54 정리본 (#106)
Browse files Browse the repository at this point in the history
  • Loading branch information
kim0527 authored Jul 16, 2024
1 parent 53468fa commit 4d162cc
Showing 1 changed file with 165 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
## 🤔 가변인수란?

> 가변인수 사용 예시
```java
static int sum(int... args) { // 명시한 타입의 인수를 0개 이상 받을 수 있다.
int sum = 0;
for (int arg : args) // 배열 args
sum += arg;
return sum;
}
```

- 동적으로 여러개의 인수를 받을 수 있게 해주는 문법

- 사용시, 인수의 개수와 길이가 같은 배열을 만들고 값들을 해당 배열에 저장하여 메서드에 건내준다.

- 0개 이상을 받을 수 있다. 즉, 0개의 인수도 받을 수 있다.


## 💁‍♂️ 만약에 인수 개수에 조건을 걸고 싶다면?

상황에 따라 **1개 이상의 인수** 와 같은 조건을 걸어야 할때가 있다.

그럴때는 어떻게 해야할까?

### 1️⃣ if문 유효성 검사

> if문 적용 사례
```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;
}
```

- 위와 같이 조건문을 통해 유효성 검사를 할 수 있다.
- 하지만 해당 방법은 **몇가지 문제가 있다.**

### ❌ 첫번째 방식의 문제점

1. 조건에 어긋나는 인수를 넣을시, **런타임에서 예외가 발생한다.**

2. 코드가 지저분 해진다.

3. 위 코드의 경우, min의 초기값을 `Integer.MAX_VALUE`를 설정하지 않고는 깔끔한 `for-each문`을 사용할 수 없다.

### 2️⃣ 대안 : 매개변수를 여러개 받도록 설정하기

> 매개변수를 1개 이상 받아야 할때
```java
static int min(int firstArgs, int... remainingArgs) { // 1개 이상 되어야 하므로 매개변수 2개 받기
int min = firstArg;
for (int arg : remainingArgs)
if (arg < min)
min = arg;
return min;
}
```

- 다음과 같이 매개변수를 여러개 받는 것으로 깔끔하게 해결 가능하다.

- 예시로 매개 변수를 1개 이상 받아야 할때, 첫번째로 평범한 매개변수로 받게 한다.

- 그렇게 되면, 0개가 들어왔을때 컴파일 단계에서 문제점을 찾을 수 있다.

## ⚠️ 주의 사항

앞에서 말했듯이, 인수의 개수와 길이가 같은 배열을 만들고 값들을 해당 배열에 저장하여 메서드에 건내준다.

즉 메서드가 호출될 때마다, **배열을 새로 하나 할당한다.**

그러면 만약 성능에 민감한 상황에서는 어떻게 해야할까?

> 대안 : 메서드 다중 정의
```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) { }
```

- 메서드를 인수의 개수마다 다중정의 하면 보완할 수 있다.

- 만약 메서드 호출의 95%가 인수를 3개 이하로 사용한다면
- 0개 ~ 4개인 것 까지 메서드를 다중정의한다.
- 그 이상의 개수는 가변인수로 정의한다.


- 즉, **자주 사용되는 개수는 다중 정의 메서드로 정의하면** 배열이 계속 새로 할당되는 것을 방지할 수 있다.

- 실제로 EnumSet의 정적 팩터리로 위와 같은 방시으로 정의되어 있다.

> EnumSet 정적 팩터리 메서드
```java
public static <E extends Enum<E>> EnumSet<E> of(E e) {
EnumSet<E> result = noneOf(e.getDeclaringClass());
result.add(e);
return result;
}

public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2) {
EnumSet<E> result = noneOf(e1.getDeclaringClass());
result.add(e1);
result.add(e2);
return result;
}

public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3) {
EnumSet<E> result = noneOf(e1.getDeclaringClass());
result.add(e1);
result.add(e2);
result.add(e3);
return result;
}

public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4) {
EnumSet<E> result = noneOf(e1.getDeclaringClass());
result.add(e1);
result.add(e2);
result.add(e3);
result.add(e4);
return result;
}

public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4, E e5){
EnumSet<E> result = noneOf(e1.getDeclaringClass());
result.add(e1);
result.add(e2);
result.add(e3);
result.add(e4);
result.add(e5);
return result;
}

@SafeVarargs
public static <E extends Enum<E>> EnumSet<E> of(E first, E... rest) {
EnumSet<E> result = noneOf(first.getDeclaringClass());
result.add(first);
for (E e : rest)
result.add(e);
return result;
}
```

## 📚 정리

#### 🙋‍♂ ️매개변수 개수에 조건을 걸고 싶다면?

- 필수 매개 변수의 개수를 일반 매개변수로 정의하자.

#### 🙋‍♂️ 가변인수를 사용함에 있어서 성능문제가 걱정된다면?

- 많이 사용되는 매개변수 개수 메서드들을 다중정의하자.

0 comments on commit 4d162cc

Please sign in to comment.