你什么时候在Java中使用varargs?

时间:2009-04-20 00:54:24

标签: java variadic-functions

我害怕varargs。我不知道该怎么用它们。

另外,让人们传递尽可能多的论点是危险的。

什么是上下文的一个例子,它是一个使用它们的好地方?

8 个答案:

答案 0 :(得分:149)

对于任何需要处理不确定数量的对象的方法,

Varargs 有用。一个很好的例子是String.format。格式字符串可以接受任意数量的参数,因此您需要一种机制来传入任意数量的对象。

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

答案 1 :(得分:78)

一个好的经验法则是:

“对任何需要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的观点。

答案 2 :(得分: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,服务器只有在意识到它不需要它们之前才必须将它们放在一个数组中。节省了很多时间。

答案 3 :(得分: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

P.S:当我没有用它时,我甚至害怕使用varargs。但现在我已经习惯了。 正如所说:“我们坚持已知,害怕未知”,所以只要尽可能多地使用它,你也会开始喜欢它:)

答案 4 :(得分:11)

Varargs是java 1.5版中添加的功能。

为什么要使用它?

  1. 如果您不知道要为方法传递的参数数量,该怎么办?
  2. 如果您想将无限数量的参数传递给方法怎么办?
  3. 这是如何运作的?

    它创建一个带有给定参数的数组&amp;将数组传递给方法。

    示例:

    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

    3

    总和是21

答案 5 :(得分:5)

我也有与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

虽然这与传入其状态可能稍后更改的任何类型的对象没有什么不同,因为数组通常是(在使用多个参数而不是数组的调用的情况下)由编译器在内部创建的新数组你可以安全地使用,这肯定是出乎意料的行为。

答案 6 :(得分:1)

我经常使用varargs作为可以使用某种过滤器对象的构造函数。例如,我们基于Hadoop的系统的很大一部分基于Mapper,它处理项目的序列化和反序列化为JSON,并应用多个处理器,每个处理器获取一个内容项并修改并返回它,或返回null拒绝。

答案 7 :(得分:1)

在Var-Args的Java文档中,很清楚var args的用法:

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

关于使用它说:

&#34;那你什么时候应该使用varargs? 作为客户,只要API提供它们,您就应该利用它们。核心API中的重要用途包括反射,消息格式化和新的printf工具。 作为一名API设计师,只有在收益真正引人注目的情况下,才应谨慎使用它们。 一般来说,你不应该重载varargs方法,否则程序员很难弄清楚调用哪些重载。 &#34;