Varargs is a helper syntax and it enables use of variable number of
arguments in a method call. In method definition variable aruguments are
indicated by elipsis (…) and is called as ‘variable arity method’ and
‘variable arity parameter’ in java language specification. While
invoking the varargs method we can use any number of arguments of type
specified and separated by comma.
Following is quoted from java language specification and gives information about what is varargs,
Things are just syntactic since once we compile the source changes into array in bytecode. Following is a snapshot from bytecode compiled from the above source.
In bytecode,
When we use method overloading we will not be able to achieve complete variability. Like the below we need to write multiple methods and I don’t think will scale enough.
In java.lang.Class we can find multiple methods using varargs and following is a sample:
Varargs Formal Syntax
FormalParameterList: LastFormalParameter FormalParameters , LastFormalParameter FormalParameters: FormalParameter FormalParameters , FormalParameter FormalParameter: VariableModifiers Type VariableDeclaratorId VariableModifiers: VariableModifier VariableModifiers VariableModifier VariableModifier: one of final Annotation LastFormalParameter: VariableModifiers Type...opt VariableDeclaratorId FormalParameterIn the above note LastFormalParameter gives the elipsis for varargs.
- We can have only one varargs in a method.
- Varargs must be the last formal parameter.
- Is it infinitely variable? No, the variable number of arguments is limited by maximum dimension of a Java array allowed in the respective JVM.
Following is quoted from java language specification and gives information about what is varargs,
If the method being invoked is a variable arity method (§8.4.1) m, it necessarily has n > 0 formal parameters. The final formal parameter of m necessarily has type T[] for some T, and m is necessarily being invoked with k >= 0 actual argument expressions.
If m is being invoked with kn actual argument expressions, or, if m is being invoked with k != n actual argument expressions and the type of the kth argument expression is not assignment compatible with T[], then the argument list (e1, … , en-1, en, …ek) is evaluated as if it were written as (e1, …, en-1, new T[]{en, …, ek}).
Varargs Sample
package com.javapapers.corejava; public class VarArgSample { static int sum(int i, int... marks) { int total = 0; for (int mark : marks) { total = total + mark; } return total; } public static void main(String[] args) { //invoking with variable arguments System.out.println(sum(1, 2, 3)); //same invocation using an array int arr[] = {2,3}; System.out.println(sum(1, arr)); } }
How Varargs Works?
When invoking with variable arguments, compiler matches the argument list from left-to-right with the formal parameters. Once initial set of parameters are matched, then whatever arguments are remaining are constructed as an array and passed to the method. In the given example, value ‘1’ is passed as argument for variable ‘i’ then there are no other arguments remaining except varargs. So the remaining values ‘2, 3’ are constructed as array and passed as parameter. This is how the dynamism is achieved.Things are just syntactic since once we compile the source changes into array in bytecode. Following is a snapshot from bytecode compiled from the above source.
In bytecode,
15 invokestatic com.javapapers.corejava.VarArgSample.sum(int, int[]) : int [32]
What was there before variable arguments?
Variable arguments was introduced long long ago in JDK 1.5 But how did we did the same thing before that? We used java array or collections and to some extent we used method overloading.When we use method overloading we will not be able to achieve complete variability. Like the below we need to write multiple methods and I don’t think will scale enough.
static int sum(int i, int j){ return i + j; } static int sum(int i, int j, int k){ return i + j + k; }We can implement the same use case as follows using java array and that is how we achieved variable arguments before varargs.
package com.javapapers.corejava; public class VarArgSample { static int sum(int i, int marks[]) { int total = 0; for (int mark : marks) { total = total + mark; } return total; } public static void main(String[] args) { //invocation using an array int arr[] = {2,3}; System.out.println(sum(1, arr)); } }Though I didn’t measure performance, I guess that there is no significant overhead in using varargs.
Varargs Gotchas
As stated above java compiler removes elipsis (…) and replaces it with an array in bytecode. JVM is not aware of varargs and so when we use reflection there is no provision to pass variable arguments and we need to construct an array and pass it.JDK’s use of Varargs
Some example use of varargs can be found in Oracle’s JDK in reflection and formatting.In java.lang.Class we can find multiple methods using varargs and following is a sample:
public Method getMethod(String name, Class... parameterTypes) throws NoSuchMethodException, SecurityException { checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader()); Method method = getMethod0(name, parameterTypes); if (method == null) { throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes)); } return method; }In java.io.PrintStream we have methods using varargs and following is a sample.
public PrintStream printf(String format, Object ... args) { return format(format, args); }We can use the above as,
package com.javapapers.corejava; public class VarArgSample { public static void main(String[] args) { System.out.printf( "%25s %n %10s ", "Hello World!", "Java Varargs: Variable Arguments."); } }
SOURCE
No comments:
Post a Comment