You may have noticed something a little funny with the code fragments in this chapter: I havenít put any try-catch blocks around them. Thatís not an oversight. PrintStream methods never throw IOExceptions. Each method in the class catchesIOException. When an exception occurs, an internal flag is set totrue. You can test this flag using thecheckError()method:
public boolean checkError()
This method returnstrueif this print stream has ever encountered an error during its lifetime. Most of the time, you just ignore this, since print streams are only used in situations where exhaustive error checking is unnecessary.
Thereís also a protectedsetError()method you can use to signal an error from a subclass:
protected void setError()
Once an error has been set, thereís no way to unset it. Generally, once aPrintStreamhas encountered an error, all further writes to it silently fail. Itís not the failure but the silence that makesPrintStream unsuitable for most applications.
I was inspired to write the first edition of this book by the numerous questions I received about why there was no printf() function in Java. Part of the goal of that edition was to explain to readers why they didnít actually need it. Thus, I was a little perturbed when Java 5 added printf(). Personally, I still donít think Java needsprintf(), but itís here now, so letís talk about it.
Theprintf()method makes heavy use of Java 5ís new varargs feature. That is, a single method definition can support any number of arguments. In this case, the signature is:
public PrintStream printf(String format, Object... args)
A typical invocation looks like this:
System.out.printf("There are %f centimeters in %f inches.", 2.54*inches, inches);
If youíre an old C hack, this is like coming home. The first argument is a format string containing both literal text and tags beginning with percent signs (%). To form the output, each tag is replaced by the corresponding argument that follows the format string. If the format string is the zeroth argument, the first tag is replaced by the first argument, the second tag by the second argument, and so forth. If there are more tags than arguments,printf()throws ajava.util.MissingFormatArgumentException. This is a subclass ofIllegalFormatException, which is a runtime exception, so you donít have to catch it. If there are more arguments than tags, the extra arguments are silently ignored.
The letter(s) after the percent sign in the format tag specify how the number is interpreted. For instance,%fmeans that the number is formatted as a floating-point number with a decimal sign.%dformats the argument as a decimal integer.%xformats the number as a hexadecimal integer.%Xalso formats the number as a hexadecimal integer but uses the uppercase letters AĖF instead of the lowercase letters aĖf to represent 10Ė15.
Most of the time, changing a lowercase conversion specifier to uppercase changes the formatted string from lowercase to uppercase. However, there are a few exceptions to this rule.
There are a couple of dozen tags for different kinds of data. Not all data is compatible. For instance, if you use%xto format adouble as a hexadecimal integer,printf()throws ajava.util.IllegalFormatConversionException. Again, this is a runtime exception and a subclass ofIllegalFormatException.
So far, this isnít anything that canít be done easily withprintln()and string concatenation. What makesprintf()more convenient for some uses is that the tags can also contain width and precision specifiers. For example, suppose we wrote the previous statement like this instead:
System.out.printf("There are %.3f centimeters in %.2f feet.", 2.54*feet, feet);
%.3fmeans that the centimeters will be formatted as a decimal number with exactly three digits after the decimal point.%.2fmeans that the number will be rounded to only two decimal places. This gives more legible output, like ďThere are 21.691 centimeters in 8.54 feetĒ instead of ďThere are 21.690925 centimeters in 8.539734 feet.Ē
A number before the decimal point in the format tag specifies the minimum width of the formatted string. For instance,%7.3fformats a decimal number exactly seven characters wide with exactly three digits after the decimal point. Those seven characters include the decimal point, so there will be exactly three digits to the left of the decimal point. If the number is smaller than 100, it will be padded on the left with spaces to make seven characters. Zeros will be added to the right of the decimal point if necessary to pad it to three decimal places.
Consider this Java 1.4 code fragment that prints a three-column table of the angles between 0 and 360 degrees in degrees, radians, and grads, using onlyprintln():
Notice how nicely everything lines up in a monospaced font? This is incredibly useful for the two dozen programmers using Java to generate reports for VT-100 terminals and letter-quality printouts on green-and-white barred computer paper. (Those readers who havenít written any software like that since 1984, and certainly those readers who werenít even born in 1984, should now see why Iím less than thrilled with the addition of this 1970s technology to a 21st-century language.)
Of course, programmers printing text in proportional-width fonts, GUI table components, HTML reports, XML documents styled with XSL stylesheets, and any other output format produced since 1992 may be less enamored of this style of programming. Anyway, Java has it now. You donít have to use it (or read the rest of this chapter) if you donít need it.