Varargs:
Variable-Length Arguments
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, but supply defaults if some of this
information is not provided. In this situation, it would be convenient to pass
only the arguments to which the defaults did not apply. Another example is the printf( ) method that is part of Java’s
I/O library. As you will see in Chapter 20, it takes a variable number of
arguments, which it formats and then outputs.
Prior to JDK 5,
variable-length arguments could be handled two ways, neither of which was
particularly pleasing. First, if the maximum number of arguments was small and
known, then you could create overloaded versions of the method, one for each
way the method could be called. Although this works and is suitable for some
cases, it applies to only a narrow class of situations.
In cases
where the maximum number of potential arguments was larger, or unknowable, a
second approach was used in which the arguments were put into an array, and
then the array was passed to the method. This approach is illustrated by the
following program:
Use an array to pass a variable number of
arguments to a method. This is the old-style
approach to variable-length arguments. class
PassArray {
static void vaTest(int v[]) {
System.out.print("Number of args: " + v.length +
Contents: ");
for(int x : v)
System.out.print(x + " ");
System.out.println();
}
public static void main(String args[])
{
Notice how an array must be created to
hold the arguments.
int n1[] =
{ 10 };
int n2[] = { 1, 2, 3
};
int n3[] = { };
vaTest(n1); // 1 arg
vaTest(n2); // 3 args
vaTest(n3); // no args
}
}
The output from the program
is shown here:
Number of args: 1 Contents: 10
Number of args: 3 Contents: 1 2 3
Number of args: 0 Contents:
In the
program, the method vaTest( ) is
passed its arguments through the array v.
This old-style approach to variable-length arguments does enable vaTest( ) to take an arbitrary number
of arguments. However, it requires that these arguments be manually packaged
into an array prior to calling vaTest( ).
Not only is it tedious to construct an array each time vaTest( ) is called, it is potentially error-prone. The varargs
feature offers a simpler, better option.
A
variable-length argument is specified by three periods (…). For example, here is how vaTest(
) is written using a vararg:
static void vaTest(int ... v) {
This syntax tells the
compiler that vaTest( ) can be
called with zero or more arguments. As a result, v is implicitly declared as an array of type int[ ]. Thus, inside vaTest(
), v is accessed using the
normal array syntax. Here is the preceding program rewritten using a vararg:
// Demonstrate variable-length arguments.
class VarArgs {
// vaTest() now uses a vararg.
static void vaTest(int ... v) {
System.out.print("Number
of args: " + v.length + " Contents: ");
for(int x : v)
System.out.print(x + " ");
System.out.println();
}
public static void main(String args[])
{
Notice how vaTest() can be called with a
variable number of arguments.
vaTest(10); // 1 arg
vaTest(1, 2, 3); // 3 args
vaTest(); // no args
}
}
The output from the program
is the same as the original version.
There are two important
things to notice about this program. First, as explained, inside vaTest( ), v is operated on as an array. This is because v is an array. The … syntax simply tells the compiler that a variable number of arguments will be used, and
that these arguments will be stored in the array referred to by v. Second, in main( ), vaTest( ) is
called with different numbers of arguments, including no arguments at all. The
arguments are automatically put in an array and passed to v. In the case of no arguments, the length of the array is zero.
A method
can have “normal” parameters along with a variable-length parameter. However,
the variable-length parameter must be the last parameter declared by the
method. For example, 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.
Remember,
the varargs parameter must be last. For example, the following declaration is
incorrect:
int doIt(int a, int b, double c, int ... vals,
boolean stopFlag) { // Error!
Here,
there is an attempt to declare a regular parameter after the varargs parameter,
which is illegal.
There is one more restriction
to be aware of: there must be only one varargs parameter. For example, this
declaration is also invalid:
int
doIt(int a, int b, double c, int ... vals, double ... morevals) { // Error!
The attempt to declare the
second varargs parameter is illegal.
Here is
a reworked version of the vaTest( )
method that takes a regular argument and a variable-length argument:
// Use varargs with standard arguments.
class VarArgs2 {
Here, msg is a normal parameter and v is a
varargs parameter.
static void vaTest(String msg, int ... v) {
System.out.print(msg + v.length + " Contents: ");
for(int x : v)
System.out.print(x + " ");
System.out.println();
}
public static void main(String args[])
{
vaTest("One vararg: ", 10);
vaTest("Three varargs: ", 1, 2, 3);
vaTest("No
varargs: ");
The output from this program
is shown here:
One vararg: 1 Contents: 10
Three varargs: 3 Contents: 1 2 3 No varargs: 0
Contents:
Overloading
Vararg Methods
You can overload a method
that takes a variable-length argument. For example, the following program
overloads vaTest( ) three times:
// Varargs and overloading.
class VarArgs3 {
static void vaTest(int ... v) {
System.out.print("vaTest(int ...): " +
"Number of args: "
+ v.length + " Contents: ");
for(int x : v)
System.out.print(x + " ");
System.out.println();
}
static void vaTest(boolean ... v) {
System.out.print("vaTest(boolean ...) " +
"Number of args: "
+ v.length + " Contents: ");
for(boolean x : v)
System.out.print(x + " ");
System.out.println();
}
static void vaTest(String msg, int ... v) {
System.out.print("vaTest(String, int ...): " +
msg + v.length + "
Contents: ");
for(int x : v)
System.out.print(x + " ");
System.out.println();
}
public static void main(String args[])
{
vaTest(1, 2, 3);
vaTest("Testing: ", 10, 20);
vaTest(true, false, false);
}
}
The output produced by this
program is shown here:
vaTest(int ...): Number of args: 3 Contents: 1 2 3
vaTest(String, int ...): Testing: 2 Contents: 10 20
vaTest(boolean ...)
Number of args: 3 Contents: true false false
This program illustrates both
ways that a varargs method can be overloaded. First, the types of its vararg
parameter can differ. This is the case for vaTest(int
...) and vaTest(boolean ...).
Remember, the ... causes the
parameter to be treated as an array of the specified type. Therefore, just as
you can overload methods by using different types of array parameters, you can
overload vararg methods by using different types of varargs. In this case, Java
uses the type difference to determine which overloaded method to call.
The second way to overload a
varargs method is to add one or more normal parameters. This is what was done
with 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.
Varargs
and Ambiguity
Somewhat
unexpected errors can result when overloading a method that takes a
variable-length argument. These errors involve ambiguity because it is possible
to create an ambiguous call to an overloaded varargs method. For example,
consider the following program:
Varargs, overloading, and ambiguity.
This program contains an error and will
not compile!
class VarArgs4 {
static void vaTest(int ... v) {
System.out.print("vaTest(int ...): " + "Number of args: " + v.length + " Contents: ");
for(int x : v)
System.out.print(x + " ");
System.out.println();
}
static void vaTest(boolean ... v) {
System.out.print("vaTest(boolean ...) " +
"Number of args: "
+ v.length + " Contents: ");
for(boolean x : v)
System.out.print(x + " ");
System.out.println();
}
public static void main(String args[])
{
vaTest(1, 2, 3); // OK
vaTest(true, false, false); // OK
vaTest(); // Error: Ambiguous!
}
}
In this program, the
overloading of vaTest( ) is
perfectly correct. However, this program 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 you will need to forego overloading and simply
use two different method names. Also, in some cases, ambiguity errors expose a
conceptual flaw in your code, which you can remedy by more carefully crafting a
solution.
Related Topics
Privacy Policy, Terms and Conditions, DMCA Policy and Compliant
Copyright © 2018-2023 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.