Friday, January 22, 2016

Topic 22: Variable-Length Arguments in Java

Beginning with JDK 5, Java has included a feature that simplifies the creation of methods that need to take a variable number of arguments. This feature is called varargs and it is short for variable-length arguments. A method that takes a variable number of arguments is called a variable-arity method, or simply a varargs method.

 

Situations that require that a variable number of arguments be passed to a method are not unusual. For example, a method that opens an Internet connection might take a user name, password, filename, protocol, and so on, and supply defaults for others. In this situation, it would be convenient to pass only the arguments to which the defaults did not apply.

 

A variable-length argument is specified by three periods (...). For ex:

returnType methodName(dataType ... varArgs)

This syntax tells the compiler that methodName( ) can be called with zero or more arguments. varArgs is implicitly declared as an array of type specified by dataType. Consider the code fragment:

// Demonstrate variable-length arguments.
static void vaTest(int ... v)
{
System.out.print("Number of args: " + v.length + " Contents: ");
for(int x : v)
System.out.print(x + " "); 
}

//Inside main()
vaTest(10); // 1 arg
vaTest(1, 2, 3);// 3 args
vaTest(); // no args

 

A method can have both “normal” and variable-length parameter. However, the variable-length parameter must be the last parameter declared by the method. For ex, this method declaration is perfectly acceptable:

int doIt(int a, int b, double c, int ... vals)

In this case, the first three arguments used in a call to doIt( ) are matched to the first three parameters. Then, any remaining arguments are assumed to belong to vals.

 

There can be only one varargs parameter in a given method. For ex, this declaration is invalid:

int doIt(int a, int b, double c, int ... vals, double ... morevals)  // Error!

 

Overloading Vararg Methods


We can overload a method that takes a variable-length argument. For ex, the following code fragment overloads vaTest( ) three times:

// Varargs and overloading.
static void vaTest(int ... v)
{
//Statements
}
static void vaTest(boolean ... v)
{
//Statements
}
static void vaTest(String msg, int ... v)
{
//Statements
}

//Inside main()
vaTest(1, 2, 3);
vaTest("Testing: ", 10, 20);
vaTest(true, false, false);

 

A varargs method can be overloaded using either of the following methods: 

  • The types of its vararg parameter can differ. For ex, vaTest(int ...) and vaTest(boolean ...).

  • Add a normal parameter. For ex, vaTest(String, int ...). In this case, Java uses both the number of arguments and the type of the arguments to determine which method to call.

Important note: A varargs method can also be overloaded by a non-varargs method. For ex, vaTest(int x) is a valid overload of vaTest( int ... x). This version is invoked only when one int argument is present. When two or more int arguments are passed, the varargs version vaTest(int...v) is used.

 

Varargs and Ambiguity


It is possible to create an ambiguous call to an overloaded varargs method. For ex, consider the code fragments:

// Varargs, overloading, and ambiguity.
static void vaTest(int ... v)
{
//Statements
}

static void vaTest(boolean ... v)
{
//Statements
}

//Inside main()
vaTest(1, 2, 3); // OK
vaTest(true, false, false); // OK
vaTest(); // Error: Ambiguous!


Here, the overloading of vaTest( ) is perfectly correct. However, the code fragments will not compile because of the following call: vaTest(); // Error: Ambiguous!

Because the vararg parameter can be empty, this call could be translated into a call to vaTest(int ...) or vaTest(boolean ...). Both are equally valid. Thus, the call is inherently ambiguous.

 

Here is another example of ambiguity. The following overloaded versions of vaTest( ) are inherently ambiguous even though one takes a normal parameter:

static void vaTest(int ... v) { // ...
static void vaTest(int n, int ... v) { // ...

Although the parameter lists of vaTest( ) differ, there is no way for the compiler to resolve the following call: vaTest(1)

Does this translate into a call to vaTest(int ...), with one varargs argument, or into a call to vaTest(int, int ...) with no varargs arguments? There is no way for the compiler to answer this question. Thus, the situation is ambiguous.

 

Because of ambiguity errors like those just shown, sometimes we will need to forego overloading and simply use two different method names.

 

Click for NEXT article.

 

Please feel free to correct me by commenting your suggestions and feedback.

No comments:

Post a Comment