Java 1.5 Tiger: A Developer's Notebook
Java 1.5 Tiger: A Developer's Notebook
5
Tiger
A Developer’s
Notebook ™
Brett McLaughlin
David Flanagan
Chapter
CHAPTER5 5
varargs
In this chapter: One of the coolest features of Java, and of any object-oriented language,
• Creating a is method overloading. While many might think Java’s strengths are its
Variable-Length typing, or all the fringe APIs it comes with, there’s just something nice
Argument List about having the same method name with a variety of acceptable argu-
• Iterating Over ments:
Variable-
Guitar guitar = new Guitar("Bourgeois", "Country Boy Deluxe",
Argument Lists GuitarWood.MAHOGANY, GuitarWood.ADIRONDACK,
• Allowing Zero- 1.718);
Length
Argument Lists Guitar guitar = new Guitar("Martin", "HD-28");
• Specify Object
Guitar guitar = new Guitar("Collings", "CW-28"
Arguments Over
GuitarWood.BRAZILIAN_ROSEWOOD, GuitarWood.ADIRONDACK,
Primitives 1.718,
• Avoiding GuitarInlay.NO_INLAY, GuitarInlay.NO_INLAY);
Automatic Array
Conversion This code calls three versions of the constructor of a (fictional) Guitar
class, meaning that information can be supplied when it’s available,
rather than forcing a user to know everything about their guitar at one
time (many professionals couldn’t tell you their guitar’s width at the nut).
Here are the constructors used:
Enums, which are public Guitar(String builder, String model) {
}
used in these
examples, are public Guitar(String builder, String model,
detailed in GuitarWood backSidesWood, GuitarWood topWood,
float nutWidth) {
Chapter 3. }
70
However, things start to get a little less useful when you want to add
information that isn’t finite. For example, suppose you want to allow
additional, unspecified features to be added to this constructor. Here are
some possible invocation examples:
Guitar guitar = new Guitar("Collings", "CW-28"
GuitarWood.BRAZILIAN_ROSEWOOD, GuitarWood.ADIRONDACK,
1.718,
GuitarInlay.NO_INLAY, GuitarInlay.NO_INLAY,
"Enlarged Soundhole", "No Popsicle Brace");
72 Chapter 5: varargs
Example 5-1. Using varargs in constructors (continued)
}
this.builder = builder;
this.model = model;
this.backSidesWood = backSidesWood;
this.topWood = topWood;
this.nutWidth = nutWidth;
this.fretboardInlay = fretboardInlay;
this.topInlay = topInlay;
}
}
What about...
...if you don’t have any features to pass in? That’s fine. Just call the con-
structor in the old way:
Guitar guitar = new Guitar("Martin", "D-18");
How do I do that?
Make sure you read “Creating a Variable-Length Argument List,” which
lets you know the most important piece of information relating to vararg
methods—variable-length arguments are treated just as arrays. So, con-
tinuing with the previous example, you could do something like this:
public Guitar(String builder, String model,
GuitarWood backSidesWood, GuitarWood topWood,
float nutWidth,
GuitarInlay fretboardInlay, GuitarInlay topInlay,
String... features) {
74 Chapter 5: varargs
public static int max(int first, int... rest) {
int max = first;
for (int i : rest) {
if (i > max)
max = i;
}
return max;
}
Simple enough, right?
What about...
...storing variable-length arguments? Since the Java compiler treats these
like arrays, an array is obviously a great choice for storage, as seen in
Example 5-2, which is a modified version of Example 5-1.
How do I do that?
Remember in “Iterating Over Variable-Length Argument Lists,” you saw
this simple method:
public static int max(int first, int... rest) {
int max = first;
for (int i : rest) {
if (i > max)
max = i;
}
return max;
}
You can call this method in several ways:
int max = MathUtils.max(1, 4);
int max = MathUtils.max(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
int max = MathUtils.max(18, 8, 4, 2, 1, 0);
76 Chapter 5: varargs
What’s not so nice is that there are many cases where you may already
have the numbers to pass in stored as an array, or at least in some col-
lected form:
// Get the numbers from some method
int[] numbers = getListOfNumbers( );
It’s impossible to just pass these numbers on to the max( ) method. You
would need to check the list length, and strip off the first object (if it’s
available), then check the type to ensure it’s an int. That would be
passed in, along with the rest of the array (which can be iterated over, or
converted manually to a suitable format). In general, this process is a real
pain and is a lot of work for what should be trivial. To get around this,
remember that this method is treated by the compiler as the following:
Autounboxing
public static int max(int first, int[] rest) helps some, as
So, by extension, you could convert max( ) to look like this: “Integer” objects
public static int max(int... values) { are freely
int max = Integer.MIN_VALUE; converted to” int”
for (int i : values) { primitives. Autoun-
if (i > max)
max = i; boxing is covered in
} Chapter 4.
return max;
}
You’ve now created a method that can easily be used with arrays:
// Get the numbers from some method
int[] numbers = getListOfNumbers( );
Anytime you have the possibility for a zero-length argument list, you
need to perform this type of error checking. Generally, a nice informative
IllegalArgumentException is a great solution.
Whatever you do,
please don’t What about...
throw a checked ...invoking this same method with normal non-array arguments? That’s
exception—you perfectly legal, of course. The following are all legitimate ways to invoke
just add hassle the max( ) method:
for programmers
int max = MathUtils.max(myArray);
using your code, int max = MathUtils.max(new int[] { 2, 4, 6, 8 });
and for what is a int max = MathUtils.max(2, 4, 6, 8);
fringe case, int max = MathUtils.max(0);
int max = MathUtils.max( );
rather than a
normal problem.
Specify Object Arguments Over
Primitives
As discussed in Chapter 4, Tiger adds a variety of new features through
unboxing. This allows you, in the case of varargs, to use object wrapper
types in your method arguments.
How do I do that?
Remember that every class in Java ultimately is a descendant of java.
lang.Object. This means that any object can be converted to an Object;
further, because primitives like int and short are now automatically
converted to their object wrapper types (Integer and Short in this case),
any Java type can be converted to an Object.
Thus, if you want to accept the widest variety of argument types in your
vararg methods, use an object type as the argument type. Better yet, go
with Object for the absolute most in versatility. For example, take a
method that did some printing:
78 Chapter 5: varargs
private String print(Object... values) {
StringBuilder sb = new StringBuilder( );
for (Object o : values) {
sb.append(o)
.append(" ");
}
return sb.toString( );
}
The basic idea here is to print anything and everything. However, the
more obvious way to declare this method is like this:
private String print(String... values) {
StringBuilder sb = new StringBuilder( );
for (Object o : values) {
sb.append(o)
.append(" ");
}
return sb.toString( );
}
The problem here is that now this method won’t take Strings, ints,
floats, arrays, and a variety of other types, all of which you might want
to legitimately print.
By using a more general type, Object, you obtain the ability to print any-
thing and everything.
How do I do that?
Before getting into the details of getting around this issue, be sure you
understand the problem. Take Java’s new printf( ) method, a real con-
venience:
System.out.printf("The balance of %s's account is $%(,6.2f\n",
account.getOwner().getFullName( ), account.getBalance( ));
80 Chapter 5: varargs
To get around this, you need to tell the compiler that you want the entire
object array, obj, treated as a single object, and not as a grouping of
arguments. Here’s the magic bullet:
out.printf("Description of object array: %s\n", new Object[] { obj });
Alternatively, here’s an even shorter approach:
out.printf("Description of object array: %s\n", (Object)obj);
In both cases, the compiler no longer sees an array of objects, it simply
sees a single Object (which just happens to be an array of objects). The
result is what you should want (at least in this rather odd scenario):
run-ch05:
[echo] Running Chapter 5 examples from Java Tiger: A Developer's
Notebook