Varargs 可变参数
原文地址:https://docs.oracle.com/javase/8/docs/technotes/guides/language/varargs.html
关键点
- 什么是可变参数:
<methodName>(<otherArgs>,<Type>... <argsName>)
- 可变参数优点:增强可读性,压缩代码长度
- 使用须知:可变参数仅能在参数表的最后一位上使用(译者注:至于原因,我简单的stackOverflow了一下,发现这么做可以简化编译器)
- 何时使用可变参数:
- API使用方:如果此API支持,好好利用此特性
- API设计方:需谨慎,仅当此特性可为此API带来明显好处时才使用
全文翻译
In past releases, a method that took an arbitrary number of values required you to create an array and put the values into the array prior to invoking the method. For example, here is how one used the MessageFormat class to format a message:
在过去的发布的版本中,对于创建一个参数个数可变的方法而言,需要你为此创建一个数组,并在调用方法前把值传入数组当中。例如,下面的例子就展示了人们如何使用MessageFormat类去格式化一个消息:
Object[] arguments = {
new Integer(7),
new Date(),
"a disturbance in the Force"
};
String result = MessageFormat.format(
"At {1,time} on {1,date}, there was {2} on planet "
+ "{0,number,integer}.", arguments);
It is still true that multiple arguments must be passed in an array, but the varargs feature automates and hides the process. Furthermore, it is upward compatible with preexisting APIs. So, for example, the MessageFormat.format method now has this declaration:
确实,多个参数必须要通过数组传入。不过可变参数的特性自动处理了这个过程,并屏蔽了实现的细节。而且,对于先前的API,它保持了向上兼容。那么,举例来说,MessageFormat.format方法现在就可有这样的声明方式:
public static String format(String pattern,
Object... arguments);
The three periods after the final parameter’s type indicate that the final argument may be passed as an array or as a sequence of arguments. Varargs can be used only in the final argument position. Given the new varargs declaration for MessageFormat.format, the above invocation may be replaced by the following shorter and sweeter invocation:
在最后参数的类型的后面有三个句号,它们表明了这个最后的参数可以通过一个数组传入,也可以通过一系列的参量传入。可变参数仅能在参数表最后一个参数的位置上被使用。为Message.format.format方法给予了新的可变参数声明方法后,上面的那个调用就可替换为一种更加优雅短小的方式:
String result = MessageFormat.format(
"At {1,time} on {1,date}, there was {2} on planet "
+ "{0,number,integer}.",
7, new Date(), "a disturbance in the Force");
There is a strong synergy between autoboxing and varargs, which is illustrated in the following program using reflection:
在自动置入置出和可变参数这两者间具有很强的协同,下面的反射案例就说明了这一点:
// Simple test framework
public class Test {
public static void main(String[] args) {
int passed = 0;
int failed = 0;
for (String className : args) {
try {
Class c = Class.forName(className);
c.getMethod("test").invoke(c.newInstance());
passed++;
} catch (Exception ex) {
System.out.printf("%s failed: %s%n", className, ex);
failed++;
}
}
System.out.printf("passed=%d; failed=%d%n", passed, failed);
}
}
This little program is a complete, if minimal, test framework. It takes a list of class names on the command line. For each class name, it instantiates the class using its parameterless constructor and invokes a parameterless method called test. If the instantiation or invocation throws an exception, the test is deemed to have failed. The program prints each failure, followed by a summary of the test results. The reflective instantiation and invocation no longer require explicit array creation, because the getMethod and invoke methods accept a variable argument list. The program also uses the new printf facility, which relies on varargs. The program reads much more naturally than it would without varargs.
这个小程序是对框架的一个完整(或者说是最小)测试。它首先在命令行中获得一个类名列表。对于每个类名,它都会利用此类名对应的无参构造方法创建一个对应的实例,并调用名为test的无参方法。如果在创建实例或调用test方式时抛出了一个异常,那么测试就会被认为是失败的。这时程序就会把每个失败打印出来,并在后面追加测试结果的总结信息。反射的实例化和调用不再需要显示的创建数组,因为getMethod()和invoke()方法接受一个可变参数列表。这个程序也使用了新的printf工具,这个新工具是依赖于可变参数的。相对于不使用可变参数而言,这段程序的读起来更加的自然,可读性更好。
So when should you use varargs? As a client, you should take advantage of them whenever the API offers them. Important uses in core APIs include reflection, message formatting, and the new printf facility. As an API designer, you should use them sparingly, only when the benefit is truly compelling. Generally speaking, you should not overload a varargs method, or it will be difficult for programmers to figure out which overloading gets called.
那么你应该在什么时候使用可变参数?作为API的使用方,只要API支持此特性,你就应该好好利用它。在核心API中应重点利用此特性的包括反射,消息格式化,新printf工具。作为API的设计者,仅当它所带来的好处是真的引人注目时,你才应该谨慎的使用它。总的来说,你不应该重载一个可变参数的方法,否则这会为编程者带来麻烦,编程者可能很难弄清楚调用的究竟是哪个重载方法。