我怕可变参数。我不知道该怎么用。

此外,让人们随心所欲地传递论点是很危险的。

使用上下文的最佳例子是什么?

评论

我不明白为什么它会是“危险的”。这并不比使用大量带有不同参数的方法更为危险。您对堆栈有疑问吗?那么您不应该这样做,因为varargs映射到按引用传递的数组。

只是想插话:避免使用您尚未完全满意的语言功能并没有什么错。比使用您不了解的功能要好得多! ;)

害怕未知是正常的。要了解更多有关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 ...)之类的方法。 ):)。

这并不是对varargs的批评,但是实际上有一些理由要“害怕”(直到您完全了解varargs的局限性);这就是存在@SafeVarargs批注的原因。 stackoverflow.com/a/14252221/1593924

#1 楼

对于需要处理不确定数量的对象的任何方法,Varargs都是有用的。 String.format是一个很好的例子。格式字符串可以接受任意数量的参数,因此您需要一种机制来传递任意数量的对象。

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


评论


数组参数还可以接收不确定数量的对象,但是varargs参数可以在调用时提供更大的灵活性和便利性。您可以编写代码来构建数组并传递它,也可以选择在varargs参数中接收Java,让Java为您完成。

– H2ONaCl
15年12月24日在23:01

是否有一些令人信服的原因,为什么您不只是传递对某些ADT的引用,无论是简单的链表还是更为成熟的List对象?当然,它仍然可以在堆栈上传递,只需使其成为在标头中具有size / count字段的结构即可。Varargs看起来就像污染,已散布到C系列的所有语言中。

–克里斯托弗·布巴赫(Christoffer Bubach)
11月23日在3:07



#2 楼

一个好的经验法则是:

“将varargs用于需要T数组(可能是T可能是任何类型)作为输入的任何方法(或构造函数)”。

这将使对这些方法的调用更容易(无需执行new T[]{...})。

您可以将此规则扩展为包括带有List<T>参数的方法,前提是该参数仅用于输入(即, list不会被该方法修改)。

另外,我将避免使用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的观点。

评论


您是否考虑添加前提条件检查,如果(args.length == 0)抛出新的RuntimeException(“ foo”);代替? (由于呼叫者违反了合同)

– Micha Wiedenmann
13年4月29日在14:46

好的,一个好的API的目的是为了尽早防止滥用,因此在编译时尽可能的避免这种情况,因此建议使用void f(T arg1,T ... args)来确保永远不要不调用它。参数,而无需等到运行时。

– jfpoilpret
13年5月10日在19:52

我认为在大多数情况下,仅调用无参数的varargs函数将完全不执行任何操作。重点是,不向varargs函数提供任何参数很可能不会造成很大的损害。

–WorldSEnder
16年11月23日在12:06

Varargs很有用,但并不等同于使用数组。 Varargs是不可修改的。因此,像泛型一样,它们会受到类型擦除的影响,这取决于工作可能是不可接受的约束。

–朱利安
17年2月14日在8:32

#3 楼

我经常使用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,则服务器只需在意识到不需要它们之前将它们放入数组即可。节省了大量时间。

评论


您可以在超类中实现调试方法,以使用反射来打印任何对象。

–路易斯·马丁内斯(Lluis Martinez)
13年8月28日在14:17

#4 楼

当我们不确定方法中要传递的参数数量时,可以使用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- PS

PS:即使我不熟悉varargs,我也很害怕使用它。但是现在我已经习惯了。
据说:“我们紧贴着已知的事物,害怕未知的事物”,所以只要尽可能多地使用它,您也将开始喜欢它:)

评论


varargs的C#等效项是“ params”。它也做同样的事情,并接受可变数量的参数。请参阅以下内容以获得更好的理解:dotnetperls.com/params

– Sarvan
2012-09-25 7:40



#5 楼

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

为什么要使用此功能?


如果不知道要传递的参数数量怎么办?方法?
如果要向方法传递无限数量的参数怎么办?

它如何工作?

它使用给定的参数创建一个数组&将数组传递给方法。

示例:

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

#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


虽然这与传递状态可能会在以后改变的任何类型的对象并没有什么不同,但是由于数组通常是(在使用多个参数而不是数组的情况下)由编译器内部创建的一个新数组可以安全使用,这肯定是意外行为。

评论


是的,但是这个例子似乎有些牵强。人们是否可能会以这种方式使用您的API?

– jfpoilpret
09年4月21日在1:27

您永远不会知道...特别是当参数的数量在调用方不是硬编码的,而且还可以将声明收集到循环中的列表中时,传入数组并不是很常见。

– Thilo
09年4月21日在1:50

我认为您的用例示例通常不会出现。有人可能会争辩说,您的API不应以这种方式使用输入数组,如果使用,则必须对其进行记录。

–劳伦斯·多尔(Lawrence Dol)
09-10-14在0:43

重载同时支持这两种方法的方法; argMethod(Object .. objList)argMethod(Object [] objList)

–thetoolman
2012年11月8日4:19



@thetoolman:我认为不可能。它将被视为重复方法。

– Thilo
2012年11月8日下午5:49

#7 楼

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

#8 楼

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

http://docs.oracle.com/javase/1.5.0/docs/guide/language/varargs.html
关于用法,它说:

“那么,什么时候应该使用varargs?
作为客户端,只要API提供它们,就应该利用它们。核心API中的用途包括反射,消息格式和新的printf工具。作为API设计人员,只有在真正令人信服的情况下,才应谨慎使用它们。
一般而言,不应过载varargs方法,否则程序员将很难弄清楚调用了哪个重载。“