Difference between double... and double[] in formal parameter type declaration
I have question: what is the difference between these two declarations?
public static void printMax(double... numbers) { ... }
public static v开发者_运维问答oid printmax(double numbers[]) { ... }
Is double... numbers
the same as double numbers[]
?
On varargs
The Type...
construct in method parameter declaration is commonly what is called varargs. In JLS, it's called the variable arity parameter.
JLS 8.4.1 Format parameters
The last formal parameter in a list is special; it may be a variable arity parameter, indicated by an elipsis following the type.
If the last formal parameter is a variable arity parameter of type
T
, it is considered to define a formal parameter of typeT[]
. The method is then a variable arity method. Otherwise, it is a fixed arity method. Invocations of a variable arity method may contain more actual argument expressions than formal parameters. All the actual argument expressions that do not correspond to the formal parameters preceding the variable arity parameter will be evaluated and the results stored into an array that will be passed to the method invocation.
To illustrate in code, this is what varargs allows you to do:
static void f(int... nums) {
for (int num : nums) {
System.out.println(num);
}
}
//...
f(1,2,3); // prints "1", "2", "3"
In contrast, without the varargs construct, you must do this:
static void g(int[] nums) {
for (int num : nums) {
System.out.println(num);
}
}
//...
g(new int[] { 1, 2, 3 }); // prints "1", "2", "3"
The varargs is what is called a syntactic sugar that hides the verbosity from you.
So to go back to your question, the difference between printMax(double... numbers)
and printmax(double numbers[])
is that the first is a variable arity method, meaning you can give it a variable number of parameters. The latter is a fixed arity method, meaning it will accept one and only parameter.
Note the quote above about T...
being really a T[]
. That is, even with varargs, you can still do the following:
f(new int[] { 1, 2, 3 }); // prints "1", "2", "3"
Here you're manually creating the array to hold the vararg parameters. In fact, if you go as far as decompiling the code, you'll find that just as JLS specified, f
does in fact take int[]
parameter, and f(1, 2, 3)
is implemented as f(new int[] { 1, 2, 3 })
.
See also
- Java language guide/varargs
Varargs gotchas
How varargs are resolved is quite complicated, and sometimes it does things that may surprise you.
Consider this example:
static void count(Object... objs) {
System.out.println(objs.length);
}
count(null, null, null); // prints "3"
count(null, null); // prints "2"
count(null); // throws java.lang.NullPointerException!!!
Due to how varargs are resolved, the last statement invokes with objs = null
, which of course would cause NullPointerException
with objs.length
. If you want to give one null
argument to a varargs parameter, you can do either of the following:
count(new Object[] { null }); // prints "1"
count((Object) null); // prints "1"
Related questions
The following is a sample of some of the questions people have asked when dealing with varargs:
- bug with varargs and overloading?
- How to work with varargs and reflection
- Most specific method with matches of both fixed/variable arity (varargs)
On when to use varargs
As the previous section showed, varargs can be tricky. Used in the right situations, however, they can lead to much more concise code.
Here's a quote from Effective Java 2nd Edition, Item 42: Use varargs judiciously (emphasis by author):
The lesson is clear. Don't retrofit every method that has a final array parameter; use varargs only when a call really operates on a variable-length sequence of values.
Not only can varargs be confusing, it can also be costly. Effective Java 2nd Edition actually recommends providing fixed-arity overloads for the most common usage scenarios.
Suppose you've determined that 95 percent of the calls to a method have three or fewer parameters. Then declare five overloadings of the method, one for each with zero through three ordinary parameters, and a single varargs for use when the number of parameters exceed three.
The book goes in much greater depth, but essentially you should only use varargs when it actually makes sense. And even in those cases, you may still want to consider providing fixed-arity overloads for performance reasons.
Related question
- Java’s varargs performance.
API links
Here are some examples where varargs makes sense:
java.util.Arrays.asList(T...)
java.util.PrintStream.printf(String format, Object... args)
java.lang.reflect.Method.invoke(Object obj, Object... args)
On array declarations
Please, please, do not make a habit of declaring arrays like this:
int x[];
You should instead put the brackets with the type, rather than with the identifier:
int[] x;
Note that this is also how arrays are referred to in the above discussions, e.g. T[]
int[]
, etc.
Related questions
- Is there any difference between
Object[] x
andObject x[]
? - Difference between
int[] myArray
andint myArray[]
in Java - in array declaration
int[] k,i
andint k[],i
- These declarations result in different types for
i
!
- These declarations result in different types for
The major difference is that in the first case, you could call printMax
with multiple arguments:
printMax(3.0, 4.0, 5.0)
whereas in the second case it would only accept a single argument (an array of double
).
Within the method body, numbers will be accessed as an array in both cases.
One thing to keep in mind is that in the first case, you can still pass a single array of double
even though the varargs notation is used.
Not exactly - double... means variable argument list - all the arguments passed at this point will be packed together as one array.
There can be only one vararg parameter in a method and it has to be the last in its prototype for obvious reasons. It will however be available in the method as an array, so in this particular case there is not much difference.
精彩评论