가변 인수
•
가변 인수(varargs, Variable Arguments)란 매개변수로 들어오는 값의 개수와 상관없이 동적으로 인수를 받을 수 있게 해주는 문법을 지칭한다.
print("홍길동");
print("홍길동", "이순신");
print("홍길동", "이순신", "유성룡");
print("홍길동", "이순신", "유성룡", "강감찬");
print("홍길동", "이순신", "유성룡", "강감찬", "이도");
Java
복사
•
이와 같이 매개변수로 들어오는 값들의 개수가 일정하지 않은 메서드가 있다면, 이 메서드를 구성하는 방법으로 메서드 오버로딩(overloading)이 있을 것이다. 하지만 매개변수의 개수가 일정치 않기 때문에 모든 경우를 만들어두어야 해서 비효율적이다.
•
이러한 상황에서 가변 인자(varargs)를 사용하면, 파라미터들을 통째로 배열로 받아 처리하기 때문에 동적으로 매개변수를 받을 수 있게 된다.
•
아래처럼 자바의 printf 메서드도 가변 인자를 활용하여 구성되어 있다.
printf(String format, Object... args)
Java
복사
자바 printf 메서드 시그니처
가변 인수 사용법
•
가변 인수를 사용하려면 메서드의 파라미터 부분에 타입… 매개변수명의 형태로 받으면 된다. 받는 파라미터들은 모아서 컴파일 시 배열로 처리되는데, 배열의 인자 개수는 제한이 없지만 배열 자료형은 매개변수의 타입으로 명시된 것을 따라간다는 것을 명심해야한다.
public static void main(String[] args) {
print("홍길동");
print("홍길동", "이순신");
print("홍길동", "이순신", "유성룡");
print("홍길동", "이순신", "유성룡", "강감찬");
print("홍길동", "이순신", "유성룡", "강감찬", "이도");
}
public static void print(String... str) {
// 가변 인수인 str 매개변수는 String[] 배열 타입으로 받아들인다.
for(String s : str) {
System.out.print(s + ", ");
}
}
Java
복사
•
만약 메서드에서 매개변수로 가변 인수 뿐만 아니라 다른 파라미터들도 받고 싶다면, 받아야 하는 파라미터들을 모두 적은 후 맨 뒤에 가변 인수를 적어주어야 한다.
가변 인수 주의점
1.
가변 인수를 사용하면 성능이 떨어진다.
•
가변 인수 메서드는 호출될 때마다 배열을 새로 할당하고 초기화하기 때문에 성능이 저하된다. 가변 인수를 꼭 써야하는 상황이라면 아래처럼 유연적인 오버로딩으로 처리하는 것이 권장된다.
class Printer {
public void print(int a1) { }
public void print(int a1, int a2) { }
public void print(int a1, int a2, int a3) { }
public void print(int a1, int a2, int a3, int... rest) { }
}
Java
복사
2.
가변 인수 자체를 오버로딩할 수 없다.
•
하나의 클래스 내에서 가변인자를 사용한 메서드를 오버로딩하면, 컴파일러가 어떤 메서드를 사용해야 하는지 구분하지 못해 에러가 발생한다.
class Printer {
public void print(String c, String... str) {
System.out.println("첫번째 메서드");
System.out.println("rest parameters : " + Arrays.toString(str));
}
public void print(String... str) {
System.out.println("두번째 메서드");
}
}
public class Main2 {
public static void main(String[] args) {
Printer p = new Printer();
// 이 메서드는 첫번째 메서드에도 두번째 메서드에서도 실행이 가능하기 때문에 컴파일러가 햇깔려 오류를 발생하게 된다.
p.print("-", "1", "2", "3");
}
}
Java
복사
3.
배열 타입 매개변수와 혼용할 수 없다.
•
가변 인자는 내부적으로 배열을 생성해서 사용하는 것이므로, 아래와 같이 배열 타입의 매개변수와 동시에 정의해 사용하는게 불가능하다.
class Printer {
public void print(String... str) {
System.out.println("첫번째 메서드");
}
public void print(String[] str) {
System.out.println("두번째 메서드");
}
}
Java
복사
4.
제네릭 타입과 함께 쓸 때는 신중히 사용해야한다.
•
아래와 같이 제네릭 타입을 노출하거나 해당 타입의 배열을 만들어 반환값으로 사용하면, 힙 오염이 발생하거나 런타임에 에러가 발생할 수 있다.
class Printer {
// 제네릭 타입으로 받는 가변 인수
public <T> T[] toArray(T... args) {
return args; // 가변 인자들을 문제없이 담기 위해 어떤 타입도 담을 수 있는 가장 상위 타입인 Object 배열을 만들어 반환
}
public <T> T[] pick(T a, T b, T c) {
T[] arr = toArray(a, b, c); // Object[] 타입 배열로 리턴된다.
return arr;
}
}
public class Main {
public static void main(String[] args) {
Printer p =new Printer();
// 제네릭 메서드에 String 타입으로 전달
String[] s = p.pick("1","2","3"); // ! ERROR - Object[] 타입을 String[] 타입으로 다운캐스팅이 불가능하다.
}
}
Java
복사