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.