Java에서 언제 varargs를 사용합니까?


192

나는 varargs를 두려워한다. 무엇을 사용 해야할지 모르겠습니다.

게다가 사람들이 원하는만큼 많은 논쟁을하게하는 것은 위험합니다.

컨텍스트를 사용하기에 적합한 컨텍스트의 예는 무엇입니까?


3
왜 "위험한"지 모르겠습니다. 다른 인수로 많은 횟수의 메소드를 호출하는 것보다 위험하지 않습니다. 스택에 관심이 있습니까? varargs는 참조로 전달되는 배열에 매핑되므로 그렇게하지 않아야합니다.
jfpoilpret 2009

66
당신이 (아직) 완전히 익숙하지 않은 언어 기능을 피하는 데 아무런 문제가 없습니다. 이해하지 못하는 기능을 사용하는 것보다 훨씬 좋습니다! ;)
Steven

2
미지의 것을 두려워하는 것은 정상입니다. varargs에 대한 자세한 내용은 docs.oracle.com/javase/tutorial/java/javaOO/arguments.html을 참조하십시오 . varargs는 두려워 할 것이 없습니다. Varargs가 유용합니다. varargs 사용법을 알면 [PrintStream.format] ( " docs.oracle.com/javase/7/docs/api/java/io/… , java.lang.Object ...)" 와 같은 메소드를 작성할 수 있습니다. ) :).
개발자 Marius Žilėnas

1
이것은 varargs에 대한 비판은 아니지만 실제로 "두려워"해야 할 이유가 있습니다 (varargs의 한계를 정확하게 이해할 때까지). 이것이 @SafeVarargs 주석이 존재하는 이유입니다. stackoverflow.com/a/14252221/1593924
Jon Coombs 2012 년

답변:


150

Varargs불확실한 수의 객체 를 처리해야하는 모든 방법에 유용 합니다 . 좋은 예가 있습니다 String.format. 형식 문자열은 여러 개의 매개 변수를 사용할 수 있으므로 원하는 수의 개체를 전달할 메커니즘이 필요합니다.

String.format("This is an integer: %d", myInt);
String.format("This is an integer: %d and a string: %s", myInt, myString);

5
배열 매개 변수는 또한 불확실한 수의 오브젝트를 수신 할 수 있지만 varargs 매개 변수는 호출 시점에서 더 많은 유연성과 편리함을 허용합니다. 배열을 빌드하고 전달하는 코드를 작성하거나 varargs 매개 변수로 수신하도록 선택할 때 Java가 처리하도록 할 수 있습니다.
H2ONaCl

79

좋은 경험 법칙은 다음과 같습니다.

"입력으로 T (T 형이 무엇이든)의 배열이 필요한 모든 메소드 (또는 생성자)에 varargs를 사용하십시오.

그렇게하면이 메소드를 쉽게 호출 할 수 있습니다 (필요하지 new T[]{...}않음).

List<T>이 인수가 입력 전용 인 경우 (즉, 목록이 메소드에 의해 수정되지 않은 경우) 인수 와 함께 메소드를 포함하도록이 규칙을 확장 할 수 있습니다 .

또한 f(Object... args)API가 명확하지 않은 프로그래밍 방식으로 미끄러지기 때문에 사용을 자제 합니다.

예를 들어, DesignGridLayout 에서 사용 JComponent하여 한 번의 호출 로 여러을 추가 할 수 있습니다 .

layout.row().grid(new JLabel("Label")).add(field1, field2, field3);

위의 코드에서 add () 메소드는로 정의됩니다 add(JComponent... components).

마지막으로, 그러한 메소드의 구현은 빈 vararg로 호출 될 수 있다는 사실을 처리해야합니다! 적어도 하나의 인수를 부과하려면 다음과 같은 추악한 트릭을 사용해야합니다.

void f(T arg1, T... args) {...}

메서드의 구현이 T... args인수 목록에있는 것보다 덜 간단하기 때문에이 트릭을 추한 것으로 생각 합니다.

이것이 varargs에 대한 요점을 분명히하는 데 도움이되기를 바랍니다.


1
전제 조건 검사 if (args.length == 0) throw new RuntimeException("foo");를 추가하는 것을 고려 했습니까 ? (발신자가 계약을 위반 한 이후)
Micha Wiedenmann

24
좋은 API의 목적은 가능한 한 빨리 오용을 방지하는 것이기 때문에 가능한 컴파일 시간에 따라서 void f(T arg1, T... args)런타임까지 기다릴 필요없이 인수없이 호출되지 않도록 항상 제안 합니다.
jfpoilpret

나는 대부분 인수없이 varargs 전용 함수를 호출하면 아무것도하지 않을 것이라고 생각합니다. 요점은 varargs 함수에 인수를 제공하지 않으면 상당한 해를 끼치 지 않을 것입니다.
WorldSEnder

Varargs는 유용하지만 배열을 사용하는 것과 동일하지 않습니다. Varargs는 수정할 수 없습니다. 따라서 제네릭과 마찬가지로 유형 삭제의 영향을 받아 작업에 따라 허용 할 수없는 제약 조건이 될 수 있습니다.
Julian

34

디버깅 목적으로 varargs를 자주 사용하여 로그에 출력합니다.

내 앱의 거의 모든 클래스에는 debugPrint () 메소드가 있습니다.

private void debugPrint(Object... msg) {
    for (Object item : msg) System.out.print(item);
    System.out.println();
}

그런 다음 클래스의 메서드 내에서 다음과 같은 호출이 있습니다.

debugPrint("for assignment ", hwId, ", student ", studentId, ", question ",
    serialNo, ", the grade is ", grade);

내 코드가 작동한다고 만족하면 로그에 너무 많은 불필요한 정보가 포함되지 않도록 debugPrint () 메서드의 코드를 주석 처리하지만 debugPrint ()에 대한 개별 호출은 주석 처리하지 않은 채로 둘 수 있습니다. 나중에 버그를 발견하면 debugPrint () 코드의 주석 처리를 제거하고 debugPrint ()에 대한 모든 호출이 다시 활성화됩니다.

물론, 나는 varargs를 쉽게 피하고 대신 다음을 수행 할 수 있습니다.

private void debugPrint(String msg) {
    System.out.println(msg);
}

debugPrint("for assignment " + hwId + ", student " + studentId + ", question "
    + serialNo + ", the grade is " + grade);

그러나이 경우 debugPrint () 코드를 주석 처리 할 때 결과 문자열로 아무것도 수행되지 않더라도 서버는 여전히 debugPrint ()를 호출 할 때마다 모든 변수를 연결하는 데 어려움을 겪어야합니다. 그러나 varargs를 사용하는 경우 서버는 필요하지 않다는 것을 인식하기 전에 배열에 배치해야합니다. 많은 시간이 절약됩니다.


4
리플렉션을 사용하여 객체를 인쇄하기 위해 수퍼 클래스에서 디버그 메소드를 구현할 수 있습니다.
Lluis Martinez

12

Varargs는 메소드에 전달할 인수의 수가 확실하지 않은 경우에 사용할 수 있습니다. 백그라운드에서 지정되지 않은 길이의 매개 변수 배열을 작성하며 이러한 매개 변수는 런타임에서 배열로 처리 될 수 있습니다.

다른 수의 매개 변수를 허용하도록 오버로드 된 메서드가있는 경우 메서드를 다른 시간에 오버로드하는 대신 varargs 개념을 사용할 수 있습니다.

또한 매개 변수 유형이 달라질 때 "Object ... test"를 사용하면 코드가 크게 단순화됩니다.

예를 들면 다음과 같습니다.

public int calculate(int...list) {
    int sum = 0;
    for (int item : list) {
        sum += item;
    }
    return sum;
}

여기서 간접적으로 int 유형 (목록)의 배열은 매개 변수로 전달되고 코드에서 배열로 처리됩니다.

더 나은 이해를 위해이 링크를 따르십시오 (이 개념을 명확하게 이해하는 데 많은 도움이되었습니다) : http://www.javadb.com/using-varargs-in-java

추신 : 심지어 나는 그것을 abt하지 않았을 때 varargs를 사용하는 것을 두려워했습니다. 그러나 지금 나는 그것에 익숙합니다. "우리는 미지의 것을 알고, 미지의 것을 두려워한다"고 말했듯이 최대한 많이 사용하면 그것을 좋아할 것입니다. :)


4
C # varargs와 동등한 것은 "params"입니다. 또한 동일한 작업을 수행하고 가변 개수의 매개 변수를 허용합니다. 더 나은 이해를 위해 이것을보십시오 : dotnetperls.com/params
Sarvan

11

Varargs는 Java 버전 1.5에 추가 된 기능입니다.

이것을 사용하는 이유는 무엇입니까?

  1. 메소드에 전달할 인수의 수를 모르는 경우 어떻게합니까?
  2. 메소드에 무제한의 인수를 전달하려면 어떻게해야합니까?

어떻게 작동합니까?

주어진 인수로 배열을 만들고 배열을 메소드에 전달합니다.

예 :

public class Solution {



    public static void main(String[] args) {
        add(5,7);
        add(5,7,9);
    }

    public static void add(int... s){
        System.out.println(s.length);
        int sum=0;
        for(int num:s)
            sum=sum+num;
        System.out.println("sum is "+sum );
    }

}

출력 :

2

합계는 12

합계는 21입니다


6

나는 varargs 관련 두려움도 있습니다.

호출자가 명시 적 배열을 메소드에 전달하면 (여러 매개 변수가 아닌) 해당 배열에 대한 공유 참조를받습니다.

이 배열을 내부에 저장해야하는 경우 호출자가 나중에 변경하지 못하도록 먼저 복제 할 수 있습니다.

 Object[] args = new Object[] { 1, 2, 3} ;

 varArgMethod(args);  // not varArgMethod(1,2,3);

 args[2] = "something else";  // this could have unexpected side-effects

배열이 일반적으로 (배열 대신 여러 개의 인수를 호출하는 경우) 컴파일러가 내부적으로 컴파일러에 의해 생성 된 새로운 객체이기 때문에 나중에 상태가 변경 될 수있는 모든 종류의 객체를 전달하는 것과 실제로 다르지 않습니다. 사용, 이것은 확실히 예기치 않은 행동입니다.


1
맞습니다. 그러나이 예제는 약간 많이 가져온 것 같습니다. 사람들이 이런 식으로 API를 사용할 가능성이 있습니까?
jfpoilpret 2009

2
당신은 알지 못합니다 ... 그리고 특히 많은 인수가 호출 측에서 하드 코딩되지 않았지만 루프의 목록으로 수집되면 배열을 전달하는 것이 드문 것은 아닙니다.
Thilo

5
나는 당신의 유스 케이스 예제가 일반적으로 말할 것 같지 않다고 생각합니다. API가 이런 식으로 입력 배열을 사용해서는 안된다고 주장 할 수 있으며, 그렇지 않으면이를 문서화해야합니다.
Lawrence Dol

두 가지를 모두 지원하는 메서드를 오버로드하십시오. argMethod (Object .. objList) argMethod (Object [] objList)
thetoolman

2
@ thetoolman : 가능하지 않다고 생각합니다. 중복 방법으로 간주됩니다.
Thilo

1

필자는 일종의 필터 객체를 사용할 수있는 생성자에 대해 varargs를 자주 사용합니다. 예를 들어 Hadoop 기반 시스템의 상당 부분은 항목 직렬화 및 직렬화 해제를 JSON으로 처리하고 각 항목을 가져 와서 수정 및 반환하거나 null을 반환하는 여러 프로세서를 적용하는 Mapper를 기반으로합니다. 거부합니다.


1

Var-Args의 Java doc에서 var args의 사용법은 매우 분명합니다.

http://docs.oracle.com/javase/1.5.0/docs/guide/language/varargs.html

사용법에 대해서는 :

"varargs를 언제 사용해야합니까? 클라이언트는 API가 제공 할 때마다이를 활용해야합니다. 핵심 API에서 중요한 용도로는 리플렉션, 메시지 형식 및 새로운 printf 기능이 있습니다. API 디자이너는이를 사용해야합니다. 일반적으로 말하면 varargs 메서드를 오버로드해서는 안됩니다. 그렇지 않으면 프로그래머가 어떤 오버로드가 호출되는지 알아내는 것이 어려울 것입니다. "

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.