-
아이템 53. 가변인수는 신중히 사용하라책/이펙티브자바 2021. 9. 17. 17:33
가변인수 (varargs) 메서드는 명시한 타입의 인수를 0개 이상 받을 수 있다.
가변인수 메서드 호출 시 인수의 개수와 길이가 같은 배열을 만들고 인수들을 이 배열에 저장하여 가변인수 메서드에 건네준다.
// 가변인수 사용법 static int sum(int... args) { int sum = 0; for (int arg : args) { sum += args; } return sum; }
예를 들어 최솟값을 구하는 메서드를 작성한다면 인수가 1개 이상이어야 하는데 0개도 받을 수 있게 설계하면 에러가 날 수 있다.
// BAD - 인수가 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; }
그래서 이런식으로 0개를 받으면 IllegalArgumentException 를 던지게 했다.
근데 이 책에서 계속 말하듯 오류는 빨리 잡아야하는데 이런식으로 하면 런타임에 실패한다.
거기다 코드도 지저분하다. 다른 방법을 사용하자.
// GOOD - 인수가 1개 이상이어야 할 때 가변인수 사용법 static int min(int firstArg, int... remainingArgs) { int min = firstArg; for (int arg : remainingArgs) { if (arg < min) min = arg; } return min; }
이렇게 첫 번째로는 평번한 매개변수를 받고, 가변인수를 두 번째로 받으면 문제가 깔끔히 사라진다.
이렇듯 가변인수는 인수 개수가 정해지지 않았을때 아주 유용하게 사용할 수 있다.
가변인수는 앞에서 말했듯 호출될 때마다 배열을 새로 하나 할당하고 초기화한다. 그래서 성능에 민감할때 문제가 될 수 있다. 다행히 유연성이 필요할 때 선택할 수 있는 패턴이 있다.
public void method1() {} public void method1(int a1) {} public void method1(int a1, int a2) {} public void method1(int a1, int a2, int a3) {} public void method1(int a1, int a2, int a3, int... rest) {}
예를 들어 메소드 호출의 95% 정도가 인수를 3개 이하로 쓴다면 이런식으로 다중정의하는 것이다.
95% 호출은 가변인수를 사용하지 않아 배열을 생성하지 않고 5% 호출만 배열을 생성하는 것이다.
// EnumSet 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; }
Java API 중 EnumSet이 이 기법의 좋은 예시이다.
결론
- 인수 개수가 일정하지 않은 메서드를 정의한다면 가변인수가 반드시 필요하다.
- 메서드 정의시 필수 매개변수는 가변인수 앞에 두자.
- 가변인수 사용시 성능문제도 고려해보자.
'책 > 이펙티브자바' 카테고리의 다른 글
아이템 61. 박싱된 기본 타입보다는 기본 타입을 사용하라 (0) 2021.09.17 아이템 54. null이 아닌, 빈 컬렉션이나 배열을 반환하라 (0) 2021.09.17 아이템 60. 정확한 답이 필요하다면 float와 double은 피하라 (0) 2021.09.16 아이템 59. 라이브러리를 익히고 사용하라 (0) 2021.09.16 아이템 52. 다중정의는 신중히 사용하라 (0) 2021.09.16