Reconsidering System.out.format().

exercise No. 147

Q:

This exercise aims at a better understanding of System.out.format() already being used in Tidy up the mess! and other exercises. Consider the following snippet:

int value = 33;
double secondValue = 114.317;

System.out.format("Just a single integer %3d\n", 
                                         value /* Just a single value to be printed */);

System.out.format("An integer %3d and a double value %6.2f\n",
                              value,                 secondValue);

Something seems to be odd here: The format() method is being called with a different number of arguments. Actually we may call it with an arbitrary number of one or more arguments. Answer the following two questions:

  1. How does this work (syntactically) ?

    Tip

    The underlying mechanism is called varargs or ellipsis being closely related to arrays. Read either of (or all):

  2. What is the role of the %... format strings?

A:

  1. At first sight these method calls appear as if the format() method had been multiply overloaded. This observation is misleading despite the fact that a related overloaded method providing an additional locale argument does indeed exist.

    According to System.out.format(...) the first argument must be of type String. Additional arguments of arbitrary type may be added in accordance with the %... format strings inside the first argument. These arguments are being passed as instances of Object. The format(...) method uses the varargs mechanism.

    Albeit being different you may compare this mechanism to the following hypothetic implementation using an array instead:

    public PrintStream format (String format, Object[] args)

    Corresponding code using this hypothetic method would read:

    System.out.format("An integer %3d and a double value %6.2f\n",
                                  new Object[]{Integer.valueOf(value), /**/
                                                        Integer.valueOf(secondValue)};

    As you can see this code is clumsy in comparison to the varargs mechanism.

  2. There is a one to one correspondence between each %... format string and its corresponding argument: If n further arguments exist the format string must contain n % format specifiers.

Consider the following snippet:

final int v = 33;
final double d = 114.317;
final short color = 255;

System.out.format("v=%d, d=%5.2f, color=%2x\n", v, d, color);

This generates the following output:

v=33, d=114.32, color=ff

We may prettify our code to better reflect the one to one correspondence between format strings and variables:

System.out.format("v=%d, d=%5.2f, color=%2x\n",
                      v,    d,           color);

Caution

A failure in providing appropriate numbers of arguments having appropriate types likely results in a runtime exception:

System.out.format("v=%d, d=%d, color=%2x\n", // Error: Using %s
                                             // rather than %f.
                           v,    d,           color);
v=33, d=Exception in thread "main"
java.util.IllegalFormatConversionException: d != java.lang.Double
	at java.util.Formatter$FormatSpecifier.failConversion(...