가변인수
가변인수(varargs) 메소드는 명시한 타입의 인수를 0개 이상 받을 수 있는 기능이다.
가변인수 메소드를 호출하면 인수의 개수와 길이가 같은 배열을 만들고 인수들을 이 배열에 저장해 가변인수 메소드에 건넨다.
static int sum(int... args) {
int sum = 0;
for (int arg : args)
sum += arg;
return sum;
}
public static void main(String[] args) {
System.out.println(sum()); // 0
System.out.println(sum(1)); // 1
System.out.println(sum(1,2)); // 3
System.out.println(sum(1,2,3)); // 6
System.out.println(sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); // 55
}
인수 개수는 런타임에 자동 생성된 배열의 길이를 통해 알 수 있다.
하지만 인수가 1개 이상이여야 할 때도 있는데, 예를들어 최소값을 찾는 메소드의 경우에는 매개변수를 보내지않으면 런타임에러다.
코드도 지저분하고 arg 유효성 검사는 명시적으로 유지, min의 초기값을 Integer.MAX_VALUE로 설정 않고는 더 명료한 for-Each문을 사용할 수도 없다. 그래서 코드를 아래와 같이 변경해서 사용하면 된다.
// 가변인수만 쓴다면 유효성 검사 명시성을 이용해 코드가 지저분해지고 인수 1개는 런타임에러가 난다.
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;
}
// 매개변수 2개로, 무조건 1개는 입력하도록 설정해 유효성 검사가 없고 코드도 깔끔해지며 인수 1개 런타임에러가 없다.
static int min(int firstArg, int... remainingArgs) {
int min = firstArg;
for (int arg : remainingArgs)
if (arg < min)
min = arg;
return min;
}
위와같이, 가변인수는 인수 개수가 정해지지 않았을 때 아주 유용하다.
대표적으로 가변인수 덕을 보고있는 자바 라이브러리의 함수를 택해보자면 printf와 핵심 리플렉션 기능이다.
가변인수가 자바 1.5부터 들어왔기때문에, 자바 1.4에서 Class와 PrintStream의 메소드를 확인하려했으나,
자바독스에서 자바 7부터 확인할 수 있어, 예측컨대 기존에는 점진적 패턴을 사용했거나 배열을 사용했을 것으로 보인다.
가변인수의 성능
성능에 민감한 상황이라면 가변인수가 걸림돌이 될 수 있다.가변 인수 메소드는 호출될 때마다 배열을 새로 할당하고 초기화하고, 이 비용을 감당할 순 없지만 유연성이 필요할 때 점진적 패턴을 사용하면 된다.
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개 이하를 사용한다면 위 코드와 같이 정해두면 된다.
그러면 메소드 호출중 5%만이 배열을 생성할 것이고, 큰 이득은 없지만 성능에 아주 민감한 특수한 상황에서는 좋은 방법이다.
EnumSet은 정적 팩토리도 이 기법을 사용해 열거 타입 집합 생성 비용을 최소화한다. EnumSet은 of 메소드에 이 기법을 사용한다.
EnumSet은 비트 필드를 대체하면서 성능까지 유지해야 해서 적절하게 사용한 예다.
인수 개수가 일정하지 않은 메소드를 정의해야 한다면 가변인수가 반드시 필요하고, 메소드를 정의할 때 필수 매개변수는 가변인수 앞에 두고, 가변인수를 사용할 땐 성능 문제까지 고려하자.
* 위 글은 EffectiveJava 3/E 책 내용을 정리한 글로, 저작권 관련 문제가 있다면 댓글로 남겨주시면 즉각 삭제조치 하겠습니다.
'Reading > Effective Java' 카테고리의 다른 글
[Effective-Java] Item 55.옵셔널 반환은 신중히 하라 (0) | 2021.11.14 |
---|---|
[Effective-Java] Item 54.null이 아닌, 빈 컬렉션이나 배열을 반환하라 (0) | 2021.11.08 |
[Effective-Java] Item 52. 다중정의는 신중히 사용하라 (0) | 2021.11.08 |
[Effective-Java] Item 51. 메소드 시그니처를 신중히 설계하라 (0) | 2021.11.08 |
[Effective-Java] Item 50. 적시에 방어적 복사본을 만들라 (0) | 2021.11.08 |