The original plan for the 1.4 release J2SE included support for formatted output. Probably due to time constraints and the fact that the feature wasn't a release driver, the capabilities were left out of the release. Now with Tiger, there is built in support for printing with format strings.
For those who grew up with Java programming and never touched C
or those who haven't lived in a C world for some time, format
strings are those funky text strings that specify output
characteristics for a bunch of variables. Instead of just
concatenating strings together with the plus sign (as in
firstName + " " + lastName), you provide a single
string to describe the output and provide the
arguments to fill the placeholders in that string at the end of the
method call: String s = String.format("%1$s %2$s", firstName, lastName).
First, let's look at the new java.util.Formatter
class. You probably won't use this class directly much, but it
provides the guts for the formatting you'll be doing. In the Javadoc
for this class, you'll find a table describing the supported
formatting options. These options range from something like %7.4f
for specifying the precision and width of a floating point number
to %tT for formatting a time to %3$s
for formatting the third argument.
Using Formatter to format output involves two
steps: creating an Appendable object to store
the output and using the format() method to put
formatted content into that object. Here's a list of implementers for the Appendable interface:
BufferedWriterCharArrayWriterCharBufferFileWriterFilterWriterLogStreamOutputStreamWriterPipedWriterPrintStreamPrintWriterStringBufferStringBuilderStringWriterWriter
An object implementing this interface can be used as the destination when
using a Formatter class by passing the object into the
Formatter constructor. Most of these classes should look
familiar, except for the StringBuilder class.
StringBuilder is nearly identical to the
StringBuffer class, with one big exception: It isn't
thread safe. If you know you are going to build up a string in a
single thread, use StringBuilder. If the building
can cross thread bounds, use StringBuffer. Listing 1 shows how you'd typically start using
Formatter:
Listing 1. Typical formatter usage
StringBuilder sb = new StringBuilder(); Formatter formatter = new Formatter(sb, Locale.US); |
After creating a Formatter class, you call its
format() method with format strings and arguments.
If you need to use a different Locale than that
sent into the constructor for part of the formatted output, you can
also pass in a Locale object to the format()
method. Listing 2 shows the two varieties of format():
Listing 2. format() methods of Formatter
public Formatter format(String format,
Object... args)
public Formatter format(Locale l,
String format,
Object... args)
|
If you want to get the value of Pi to 10 digits of precision, the code in Listing 3
will put that value into the StringBuilder and print
the output. Printing the formatter object will display the
content of the Appendable object.
Listing 3. Demonstrating a Formatter
import java.util.Locale;
import java.util.Formatter;
public class Build {
public static void main(String args[]) {
StringBuilder sb = new StringBuilder();
Formatter formatter = new Formatter(sb, Locale.US);
formatter.format("PI = %12.10f", Math.PI);
System.out.println(formatter);
}
}
|
Don't forget to compile with the -source 1.5
option or the compiler won't recognize the variable argument
list. Because formatting output and sending it to the console are
common tasks, there are conveniences available to this behavior. We'll look at those next.
The PrintStream class contains the definition of the
common System.out and System.err objects
for writing to standard output and standard error, respectively.
Introduced in Tiger are two new constructors (for going straight
to a file) and six methods for formatting support (three sets of
pairs). The first pair is different versions of the
append() method. This pair implements the new
java.lang.Appendable interface. You would typically not
call these methods directly. The ones you would call directly are
format() and printf(), where the
printf() versions are just convenience wrappers
for the format() versions, as shown in Listing 4:
Listing 4. PrintStream.format methods
public PrintStream format(String format,
Object... args)
public PrintStream format(Locale l,
String format,
Object... args)
|
Keep in mind the new variable argument support, which is designated
by the ... shown in Listing 4 above.
Listing 5 demonstrates the use of the format() method of
PrintStream to print today's date:
Listing 5. Example PrintStream.format usage
/
import java.util.Calendar;
public class Now {
public static void main(String args[]) {
System.out.format(
"Today is %1$tB %1$te, %1$tY.",
Calendar.getInstance()
);
}
}
|
The output from running this program is Today is April 2, 2004., although the actual output depends on the date you run the program. The %1$tB formatting string in the code above tells the program to use the first argument and print out the full month name for the date object. The
%1$te formatting string means to display the day of the month and the
%1$tY formatting string is for the four-digit year. Other options for
printing dates and times are shown in the Javadoc for the
Formatter object.
The String class has two new static format()
methods that work similarly to their printf()
equivalents. Send a format string and arguments (with a possible
Locale) and use what is
specified in the format string to convert the arguments. In the case of the String
version of the method, the results are sent back as a
String object, instead of going through the stream.
These methods aren't overly spectacular, but they
allow you to avoid using the Formatter object
directly and creating an intermediate StringBuilder.
Everything you've seen so far describes how to use the new formatting capabilities to format existing
objects and primitive types. If you want to provide support for using your own objects
with Formatter, that's where the
Formattable interface comes into play. By implementing
the single formatTo() method shown in Listing 6 in your
own class, you can use your own classes with format strings:
Listing 6. Formattable interface
void formatTo(Formatter formatter,
int flags,
Integer width,
Integer precision)
|
Listing 7 demonstrates the use of the Formattable interface by
providing a simple class with a name property. That name is displayed in the output,
with support for controlling the width of the output and the justification.
Listing 7. Example formattable usage
import java.util.Locale;
import java.util.Formatter;
import java.util.Formattable;
public class MyObject implements Formattable {
String name;
public MyObject(String name) {
this.name = name;
}
public void formatTo(
Formatter fmt,
int f,
Integer width,
Integer precision) {
StringBuilder sb = new StringBuilder();
if (precision == null) {
// no max width
sb.append(name);
} else if (name.length() < precision) {
sb.append(name);
} else {
sb.append(name.substring(0, precision - 1)).append('*');
}
// apply width and justification
if ((width != null) && (sb.length() < width)) {
for (int i = 0, n=sb.length(); i < width - n; i++) {
if ((f & Formattable.LEFT_JUSTIFY) == Formattable.LEFT_JUSTIFY) {
sb.append(' ');
} else {
sb.insert(0, ' ');
}
}
}
fmt.format(sb.toString());
}
public static void main(String args[]) {
MyObject my1 = new MyObject("John");
MyObject my2 = new MyObject("Really Long Name");
// First / Using toString()
System.out.println("First Object : " + my1);
// Second / Using Formatter
System.out.format("First Object : '%s'\n", my1);
// Second / Using Formatter
System.out.format("Second Object: '%s'\n", my2);
// Second / Using Formatter with width
System.out.format("Second Object: '%10.5s'\n", my2);
// Second / Using Formatter with width and left justification
System.out.format("Second Object: '%-10.5s'\n", my2);
}
}
|
Running this program produces the output in Listing 8. The first two
lines demonstrate the difference between using toString
and Formatter. The last three show options for
width and justification control.
Listing 9. Example formattable output
First Object : MyObject@10b62c9 First Object : 'John' Second Object: 'Really Long Name' Second Object: ' Real*' Second Object: 'Real* ' |
Getting a grasp of all the formatting options available with
Formatter will take a little time, unless you are
familiar with them from the C world. Some minor
differences exist, but for the most part the
behaviors are very similar. One key difference with the Java platform is that when the
formatting string is invalid, an exception will be thrown.
Be sure to take a long look at the formatting strings
available, as shown in the Formatter class Javadoc.
When creating your own custom classes, not only should you provide a
toString() implementation, but implementing
the Formattable interface will typically be
beneficial.
| Name | Size | Download method |
|---|---|---|
| j-tiger04024code.zip | HTTP |
Information about download methods
- Download the J2SE 1.5 from the Sun Developer Network.
- Download the source code examples used in this article.
- Check out the 1.5.0 Javadocs to learn about what's new:
- Formatter class
- Formattable interface
- Appendable interface
- String class
- StringBuilder class
- PrintStream class
- Learn about "Formatting numbers and currency" (developerWorks, August 2003) from an earlier Magic with Merlin column.
- Try the "Getting started with new I/O (NIO)" (developerWorks, July 2003) tutorial to learn more about the NIO libraries.
- Examine the progress of Tiger (J2SE 1.5) with JSR 176.
- Email bug reports to Sun at j2se-beta-feedback@sun.com.
- Read the complete set of Taming Tiger tips from John Zukowski. And if you're still working with J2SE 1.4, you'll want to read Magic with Merlin series, too.
- Find hundreds more Java technology resources on the
developerWorks Java technology zone.
- Browse for books on these and other technical topics.

John Zukowski conducts strategic Java consulting with JZ Ventures, Inc. and is working with SavaJe Technologies to develop a next-generation mobile phone platform. His latest books are Mastering Java 2, J2SE 1.4 (Sybex, April 2002) and Learn Java with JBuilder 6 (Apress, March 2002). Reach him at jaz@zukowski.net.
Comments (Undergoing maintenance)





