[Java] 가변인자 (varargs)

조민서·2022년 8월 20일
3

JAVA

목록 보기
6/17
post-thumbnail
post-custom-banner
  • 기존에는 메서드의 매개변수 개수가 고정적이었나 JDK1.5부터 동적으로 지정해 줄 수 있게 되었으며, 이 기능을 가변인자 (variable arguments)라고 한다.

  • 가변 인자는 타입... 변수명과 같은 형식으로 선언하며, PrintStream클래스의 printf()가 대표적인 예이다.

  • public PrintStream printf(String format, Object... args) { ... }

    위와 같이 가변인자 외에도 매개변수가 더 있다면, 가변인자를 매개변수 중에서 제일 마지막에 선언해야 한다. 그렇지 않으면, 컴파일 에러가 발생한다. 가변인자인지 아닌지를 구별할 방법이 없기 때문에 허용하지 않는 것이다.


가변인자는 매개변수 중에서 제일 마지막에 선언해야 한다.

public class Main {
    public static void main(String[] args) {
        System.out.println(varargsEx("010-1234-5678","jo", "min", "seo"));
        System.out.println(varargsEx("010-5678-1234", "gam", "mi"));
    }

    static String varargsEx(String mail, String... str) {
        mail += " ";
        for (String s : str) {
            mail += s;
        }
        return mail;
    }
}

출력
010-1234-5678 jominseo
010-5678-1234 gammi


가변인자를 매개변수 앞에 선언할 경우 컴파일 에러 발생

public class Main {
    public static void main(String[] args) {
        System.out.println(varargsEx("jo", "min", "seo", "010-1234-5678"));
        System.out.println(varargsEx("gam", "mi", "010-5678-1234"));
    }
    
    // 컴파일 에러 발생 - 가변인자는 항상 마지막 매개변수이어야 한다.
    static String varargsEx(String... str, String mail) {
        mail += " ";
        for (String s : str) {
            mail += s;
        }
        return mail;
    }
}

컴파일 에러 발생: java: varargs parameter must be the last parameter
가변인자를 제일 마지막에 선언하지 않을 경우, 가변인자인지 아닌지를 구별할 방법이 없기 때문에 허용하지 않는 것이다.


가변인자 활용 방법

만일 여러 문자열을 하나로 결합하여 반환하는 concatenate메서드를 작성한다면, 아래와 같이 매개변수의 개수를 다르게 해서 여러 개의 메서드를 작성해야할 것이다.

  • String concatenate (String s1, String s2) { ... }
  • String concatenate (String s1, String s2, String s3) { ... }
  • String concatenate (String s1, String s2, String s3, String s4) { ... }

이럴 때, 가변인자를 사용하면 메서드 하나로 간단히 대체할 수 있다.
String concatenate (String... str) { ... }

이 메서드를 호출할 때는 아래와 같이 인자의 개수를 가변적으로 할 수 있다. 심지어는 인자가 아예 없어도 되고 배열도 인자가 될 수 있다.

  • concatenate()
  • concatenate("jo")
  • concatenate("jo", "min", "seo")
  • concatenate(new String[] {"A", "B"})

가변인자 활용 예시

public class Main {
    public static void main(String[] args) {
        System.out.println(concatenate()); // 인자가 없음
        System.out.println(concatenate("jo")); // 인자가 하나
        System.out.println(concatenate("jo", "min", "seo")); // 인자가 셋
        System.out.println(concatenate(new String[] {"A", "B"})); // 인자가 배열
    }

    static String[] concatenate(String... str) {
        return str;
    }
}

가변인자는 신중히 사용하자.

아마 눈치 챈 사람도 있을것이다. 가변인자는 내부적으로 배열을 이용하는 것이다. 그래서 가변인자가 선언된 메서드를 호출할 때마다 배열이 새로 생성된다.
가변인자가 편리하지만, 이런 비효율이 숨어있으므로 꼭 필요한 경우에만 가변인자를 사용하자.

또한 가변인자 메서드를 오버로딩 할 때도 주의해야 하는데, 아래에 주의점을 적어놨다.


매개변수 타입을 배열로하면 가변인자와 똑같은거 아닌가?

public class Main {
    public static void main(String[] args) {
        System.out.println(concatenate()); // 에러. 인자가 필요함
        System.out.println(concatenate(null)); // 인자로 null을 지정
        System.out.println(concatenate(new String[0])); // 인자로 배열을 지정
    }

    static String[] concatenate(String[] str) {
        return str;
    }
}

매개변수의 타입을 배열로 하면, 반드시 인자를 지정해 줘야하기 때문에, 위의 코드에서처럼 인자를 생략할 수 없다. 그래서 null이나 길이가 0인 배열을 인자로 지정해줘야 하는 불편함이 있다.

C언어와 달리 자바에서는 길이가 0인 배열을 생성하는 것이 허용된다.


가변인자 오버로딩시 주의점

public class Main {
    public static void main(String[] args) {
        String[] strArr = {"100", "200", "300"};

        System.out.println(concatenate("", "100", "200", "300")); // 에러 발생 
        System.out.println(concatenate("_", strArr));
        System.out.println(concatenate(",", new String[] {"1", "2", "3"}));
        System.out.println(concatenate(",", new String[0]));

    }

    static String concatenate(String... args) {
        return concatenate("", args);
    }

    static String concatenate(String delim, String... args) {
        String result = "";

        for(String str : args) {
            result += str + delim;
        }

        return result;
    }
}

concatenate메서드는 매개변수로 입력된 문자열에 구분자를 사이에 포함시켜 결갑해서 반환한다.
가변인자로 매개변수를 선언했기 때문에 문자열을 개수의 제약없이 매개변수로 지정할 수 있다.

  • String[] strArr = {"100", "200", "300"};
  • System.out.println(concatenate("-", strArr));
    위의 두 문장을 하나로 합치면 아래와 같이 쓸 수 있다.

System.out.println(concatenate("-", new String[] {"100", "200", "300"}));

그러나 아래와 같은 문장은 허용되지 않는다.

  • System.out.println(concatenate("-", {"100", "200", "300"}));
  • System.out.println(concatenate("-", "100", "200", "300"));

에러 내용
java: reference to concatenate is ambiguous
both method concatenate(java.lang.String...) in Main and method concatenate(java.lang.String,java.lang.String...) in Main match

에러의 내용을 살펴보면 두 오버로딩된 메서드가 구분되지 않아서 발생하는 것임을 알 수 있다. 가변인자를 선언한 메서드를 오버로딩하면, 메서드를 호출했을 때 이와 같이 구별되지 못하는 경우가 발생하기 쉽기 때문에 주의해야 한다. 가능하면 가변인자를 사용한 메서드는 오버로딩 하지 않는 것이 좋다.

profile
내 두뇌는 휘발성 메모리다. 😪
post-custom-banner

0개의 댓글