Java Tech: Using Variable Arguments Blog



    Basic Syntax and Uses
    Tiger Uses Variable Arguments
       Process Building
    C-styleprintf() and scanf()

    Welcome to Java Tech. This new column explores all kinds of Java technology in terms of theory and practicality. For example, one article might investigate Tiger's generics language feature, whereas another article might apply Java to the construction of a web shopping cart application or a "smart" computer game that can beat the pants off many game players. I hope you enjoy the adventure.

    Speaking of Tiger (also known as J2SE 5.0), this article focuses on the new variable arguments language feature. After examining basic syntax, we'll cover diverse uses for variable arguments.

    Note: This column is based on J2SE 5. Sun has established an external version number of 5.0 and an internal version number of 1.5.0 to this release of the Java 2 platform.

    Basic Syntax and Uses

    Tiger's variable arguments language feature makes it possible to call a method with a variable number of arguments. Before making that call, the rightmost parameter in the method's parameter list must conform to the following syntax:

    type ... 

    The ellipsis (...) identifies a variable number of arguments, and is demonstrated in the following summation method.

    static int sum (int ... numbers) { int total = 0; for (int i = 0; i < numbers.length; i++) total += numbers [i]; return total; }

    Call the summation method with as many comma-delimited integer arguments as you desire -- within the JVM's limits. Some examples:sum (10, 20) and sum (18, 20, 305, 4).

    Look closely at the method declaration above, and you'll discover that variable arguments is implemented in terms of arrays. (numbers.length and numbers [i] are the giveaways.) It turns out that the ellipsis is just syntactic sugar for having the compiler create and initialize an array of same-typed values and pass that array's reference to a method. For example, the compiler converts the method call sum (10, 20) into an equivalent sum (new int [] {10, 20}) method call.

    Can you change int ... numbers to int [] numbers and still invoke sum (10, 20)? Answer: no. If you try to do that, the compiler reports an error. Usesum (new int [] {10, 20}) instead.

    Summing a list of integers is one basic use for variable arguments. Computing the average of a list of floating-point numbers, concatenating a list of strings into a single string, and finding the maximum/minimum values in lists of floating-point numbers are other basic uses. The source code demonstrates these basic uses, to give you more exposure to variable arguments.

    // class BasicUses { public static void main (String [] args) { System.out.println ("Average: " + avg (20.3, 3.1415, 32.3)); System.out.println ("Concatenation: " + concat ("Hello", " ", "World")); System.out.println ("Maximum: " + max (30, 22.3, -9.3, 173.2)); System.out.println ("Minimum: " + min (30, 22.3, -9.3, 173.2)); System.out.println ("Sum: " + sum (20, 30)); } static double avg (double ... numbers) { double total = 0; for (int i = 0; i < numbers.length; i++) total += numbers [i]; return total / numbers.length; } static String concat (String ... strings) { StringBuilder sb = new StringBuilder (); for (int i = 0; i < strings.length; i++) sb.append (strings [i]); return sb.toString (); } static double max (double ... numbers) { double maximum = Double.MIN_VALUE; for (int i = 0; i < numbers.length; i++) if (numbers [i] > maximum) maximum = numbers [i]; return maximum; } static double min (double ... numbers) { double minimum = Double.MAX_VALUE; for (int i = 0; i < numbers.length; i++) if (numbers [i] < minimum) minimum = numbers [i]; return minimum; } static int sum (int ... numbers) { int total = 0; for (int i = 0; i < numbers.length; i++) total += numbers [i]; return total; } }

    Look closely at and you'll discover a second Tiger innovation: java.lang.StringBuilder. I use that class, instead of java.lang.StringBuffer, in the concatenation method because StringBuilder's lack of synchronization offers better performance thanStringBuffer. (Why call a synchronized method and obtain the resulting performance hit, no matter how small, when it's not necessary?)

    Tiger Uses Variable Arguments

    As you've just seen, variable arguments are useful in simple methods. But they are even more useful in the Tiger SDK. That SDK uses variable arguments in the areas of reflection, process building, and formatting (and probably other areas that I have yet to discover.)


    java.lang.Class and a fewjava.lang.reflect classes (such as Methodand Constructor) reveal methods that employ the new... variable arguments syntax. Examples includeClass's public Method getMethod(String name, Class ... parameterTypes) and Method'spublic Object invoke(Object obj, Object ... args). Those methods are callable, either in the traditional manner or in the new variable arguments manner. Consider an example where a classfile represents the class below:

    class SomeClass { public void someMethod (String strArg, int intArg) { System.out.println ("strArg = " + strArg); System.out.println ("intArg = " + intArg); } }

    Now suppose you want to dynamically load theSomeClass classfile and reflectively invoke its solitary method. That task can be accomplished, in the traditional manner, with the code fragment below:

    Class [] argTypes = { String.class, int.class }; /* Note: Java 1.5's autoboxing language feature lets you replace "new Integer (20)" with "20". The compiler converts "20" to "new Integer (20)". This code fragment assumes an earlier version of Java -- which is why "new Integer (20)" is specified instead of "20". */ Object [] methodData = { "A", new Integer (20) }; Class c = Class.forName ("SomeClass"); Method m = c.getMethod ("someMethod", argTypes); m.invoke (c.newInstance (), methodData);

    In contrast, variable arguments let you express the code fragment above more compactly, as follows:

    Class c = Class.forName ("SomeClass"); Method m = c.getMethod ("someMethod", String.class, int.class); m.invoke (c.newInstance (), "A", 20);

    You save keystrokes and the code is much easier to read.

    Process Building

    The new java.lang.ProcessBuilder class makes it possible to build operating system processes and manage a collection of process attributes (the command, an environment, a working directory, and whether or not the error stream is redirected). One of that class's constructors and the public ProcessBuilder command(String ... command) method use the new variable arguments syntax to simplify the specification of a command for execution and its arguments. For example, to execute Windows' notepad program, and have that program load the autoexec.bat batch file from the root directory (on the current drive), specify the code fragment below:

    Process p = new ProcessBuilder ("notepad", "\\autoexec.bat").start ();

    The constructor specifies the command to execute, along with a variable number of arguments to pass to the command. Thestart() method call starts the command executing and returns a java.lang.Process reference for retrieving process-exit status (in addition to other tasks).

    Without variable arguments, you would probably specify the above code fragment in the following manner:

    String [] commandAndArgs = { "notepad", "\\autoexec.bat" }; Process p = new ProcessBuilder (commandAndArgs).start ();

    Once again, variable arguments makes the code easier to read.


    Possibly the major reason for including variable arguments (and autoboxing) in Tiger is the new java.util.Formatterclass. In combination with its java.lang.Appendablehelper interface, Formatter formats data values of arbitrary data types and outputs the formatted results to arbitrary destinations.

    Unless your application has specialized needs, you won't need to work directly with Formatter andAppendable. Instead, you'll work with one of theformat methods found in the following,, and java.lang.String. Behind the scenes, those classes work with the Formatter class (and sometimes withAppendable, too).

    PrintStream, PrintWriter, andString each present two format methods. One method takes a java.util.Locale argument, where the other method does not. The return types vary, as well.PrintStream's format methods returnPrintStream references, PrintWriter'sformat methods return PrintWriterreferences, and String's format methods return String references. And finally,String's format methods are static methods, whereas the format methods in the other two classes are instance methods. The following code fragment demonstrates two of these format methods:

    String s = String.format ("%.2f", 1.256); System.out.format ("%05d", 1234);

    String's locale-less format method reveals a pattern argument, consisting of %.2f("format a floating-point value such that there are exactly two digits after the decimal point, and employ rounding if necessary"), followed by the floating-point value to format: 1.256. The formatted result -- 1.26 -- returns as aString, whose reference assigns to s.

    Similarly, PrintStream's locale-lessformat method takes a pattern followed by a single value. However, the %05d pattern states that an integer is to be formatted to a minimum of five digits. If there are not enough digits, leading zeroes display to the left of the non-zero digits. Instead of returning the result --01234 -- for storage, PrintStream'sformat outputs 01234 to a stream (the standard output stream, in this case).

    Note: java.text.MessageFormat also reveals aformat method with a variable number of arguments. Unlike the previously discussed format methods, thisformat method is not a wrapper forFormatter.

    C-style printf() andscanf()

    Coming from a C background, I equate variable arguments with what are probably the most popular functions in C's standard library: printf() and scanf(). (It's a bit silly, but either function pops into my mind when someone mentions variable arguments.) For the uninitiated, C developers create formatted output by calling printf(), and obtain formatted input by calling scanf().

    My fondness for those functions resulted in considerable pleasure when I found a pair of printf methods in each of the PrintStream and PrintWriterclasses. It doesn't matter that they exist as convenience methods delegating to equivalent format methods. It's still nice to have official Java versions of printf().

    Official versions of scanf() don't exist:scanf() relies upon pointers, which Java doesn't support. However, Tiger introduces a newjava.util.Scanner class that makes up for the lack ofscanf(). This class lets you create a simple regular expression- oriented text scanner, for scanning primitive types and strings from an input source.

    The following source code demonstrates one of the printf methods andScanner performing the equivalent of some commented-out C code.

    // import java.util.Scanner; class FormattedIO { public static void main (String [] args) { /* // Execute the equivalent of the following // C code fragment. int i; float f; char s [50]; printf ("Enter three values -- integer float string: "); scanf ("%d %f %s", &i, &f, s); printf ("%d %f %s\n", i, f, s); */ System.out.printf ("Enter three values -- " + integer float string: "); Scanner sc = new Scanner (; int i = sc.nextInt (); float f = sc.nextFloat (); String s = sc.nextLine (); System.out.printf ("%d %f %s\n", i, f, s); } }

    After prompting the user to enter three values,FormattedIO creates a scanner that scans characters from standard input. The program next calls the methodsnextInt(), nextFloat(), andnextString() to extract an integer, followed by a floating-point value, followed by a string of characters -- up to, but not including the line terminator -- from the standard input stream. Finally, System.out.printf ("%d %f %s\n", i, f, s); formats those values into a sequence of characters that it sends to the standard output.


    Variable arguments are a subtle but quite useful feature in Tiger's arsenal of new language features. Uses range from simple methods to reflection, process building, and formatting. Perhaps the versatility of variable arguments comes out best in the newprintf methods. Although scanf methods that use variable arguments (in the C sense) are not possible, Tiger's inclusion of a Scanner class makes up for that deficiency.

    You really didn't think I'd let you get away without doing some homework, did you? I have a couple of exercises for you to work on. Answers will appear next month:

    1. Is void foo (String ... args, int x) { } legal Java code? Why or why not?

    2. Create a PrintFDemo application that demonstrates many of the formatting options made available byFormatter.

    Next month, Java Tech enters the realm of zero sum perfect information games, such as chess.