Introduction to Printf for Java

If you're a veteran C programmer (as many Java programmers are), you have probably become familiar with the printf function. The printf function is an uncontested success story in software component reuse; it is probably the single most reused software component in all of programming history.

If you're not a veteran C programmer, however, then you probably have no clue what I'm talking about. The printf function, a small part of the well-known C package called stdio, is an extremely versatile tool for formatting and outputing textual data. Whether your program outputs numbers, characters, or strings, chances are good that printf can format it just the way you want.

I was once an enthusiastic C programmer, but it didn't take me long to betray C for Java. After my "conversion," however, I soon realized that I would not be able to survive without some essential C functions, including an easy way to format text. So I ported the printf function to Java. This port has been incorporated into Lava, Sharkysoft's proprietary Java class library, and is also available as a separate product.


Depending on your programming style, Printf for Java's printf features can be employed in many ways, giving each programmer the freedom to use printf in the manner with which he or she is most comfortable. Examples of a few usage patterns are given in this article.

Consider the following formatted output:

(    3,   1.73,        0x9)
(    9,   3.00,       0x51)
(   27,   5.20,      0x2d9)
(   81,   9.00,     0x19a1)
(  243,  15.59,     0xe6a9)
(  729,  27.00,    0x81bf1)
( 2187,  46.77,   0x48fb79)
( 6561,  81.00,  0x290d741)
(19683, 140.30, 0x17179149)

This output is a set of triplets, listing

  1. the first nine powers of 3,
  2. the square roots of those powers, rounded to two decimal places, and
  3. the squares of those powers, in hexadecimal notation.

As you study the code examples in this article, remember that each example produces exactly the output shown above. Before reading on, try to imagine how you might do this -- that is, in Java, how would you output neatly formatted numbers, in a variety of styles, to produce a table like the one shown above? If you're up for the challenge, set this article aside and give it a shot. Then come back, and let's compare results.


feeling like a C programmer

If you took my challenge, then you probably found out that with Java's class library alone, it takes a lot of work. But it doesn't have to! The printf features in Printf for Java are designed to make formatted numerical output extremely easy. Examine the following code:

for (int i = 3; i <= 20000; i *= 3) Stdio.printf ( "(%5d, %6.2f, %#10x)\n", new Object[] { new Integer (i), new Float ((float) Math.sqrt ((double) i)), new Integer (i * i) } );

In this example, printf is a method of Stdio. The first parameter to printf -- that strange-looking string -- is called the format string. This format string lists the items that printf will output:

  1. First, the string "(";
  2. next, an int, right-aligned in a 5-character field;
  3. next, the string "";
  4. next, a float, rounded to two decimal places, right-aligned in a 6-character field;
  5. again, the string "";
  6. another int, in standard hexadecimal, right-aligned in a 10-character field;
  7. and finally, the string ")\n".

Observe that wherever numerical substitutions occur, there are special codes, each beginning with a '%' character and ending with a letter. These codes are called format specifiers, or substitution flags. Whenever these flags are present in the format string, additional arguments must be supplied, which are formatted and included in the output at the substitution points. These substitution arguments are given in the second parameter, an Object array. An Object array is used because the format string may contain any number substitution flags, each calling for any type of data. Since Java does not support variable argument lists, the generic Object array is the most suitable alternative.

why Object arrays?

The C programming language allows direct (though dangerous) manipulation of pointers. Thus, in C, variable-length argument lists are allowed and often used. Java, however, enforces safer memory access rules and hence cannot allow variable-length argument lists. The next best thing in Java is the variable-length Object array, so that's what Printf for Java uses.

speeding things up

In the previous code example, the format string must be interpreted before it can be used to format the data in the Object array. If you're going to print a long list of items that all follow the same format, you can speed things up by making sure the format string gets interpreted only once, before entering the loop, and then reusing the interpretation throughout each iteration of the loop. The following example demonstrates how:

PrintfFormatString fmt = new PrintfFormatString ("(%5d, %6.2f, %#10x)\n"); for (int i = 3; i <= 20000; i *= 3) Stdio.printf ( fmt, new Object[] { new Integer (i), new Float ((float) Math.sqrt ((double) i)), new Integer (i * i) } );

In this example, fmt, a PrintfFormatString object, is initialized before the loop. When fmt is initialized, the format string is "compiled" into a "formatting engine." Since this step occurs before the loop, the same engine can be used and reused in each pass through the loop, resulting in more efficient execution. If execution speed is important, you should apply this technique wherever you believe the same format string will be used over and over again. Preallocate your format strings and save them away in static variables. Why parse a format string 100 times, when just once will do?

the easy road

The previous two examples use Object arrays, along with primitive encapsulation classes (i.e., Integer, Float, etc.), to pass the substitution arguments. If you don't like doing it this way, there is an alternative:

for (int i = 3; i <= 20000; i *= 3) Stdio.printf ( "(%5d, %6.2f, %#10x)\n", new Va_list () . add (i) . add ((float) Math.sqrt ((double) i)) . add (i * i) );

In this example, the Va_list class is used to insulate the programmer from the rigors of manually building an Object array. Note that the add method is overloaded for each type of primitive data (int, float, long, etc.). The result is an object that Printf for Java automatically converts into the required Object array.

This kind of parameter-passing technique is not uncommon in situations where methods require argument lists of variable size and type. However, I do not recommend using it if you can avoid it. The reason for this is that it simply is not as efficient as explicit Object array creation. The reason? Internally, the Object array must eventually be created anyway.

To make matter worse, most list-building classes, such as Va_list, rely on a growable vector of Objects (such as java.util.Vector), since the size of the vector cannot be computed at compile time. Some of this inefficiency can be averted by giving a prediction of the vector's final size when the vector is first created. (For example, in the code shown above, the expression "new Va_list ()" ought to be replaced with "new Va_list (3)", since it is clear that add will be called only 3 times.) However, the overhead of all the add calls is still incurred, so the actual speed-up will be minimal.

staying platform-neutral

In our running example, each line of formatted output is terminated with the newline character ('\n'). While this works perfectly on Unix machines -- and most of the time on Win32 machines -- it may not always work on other platforms. This is because different platforms use different line-ending characters. If you're writing cross-platform Java software, and you need your programs to terminate each line of output in a manner that is appropriate for the platform on which the software is running, then you should not use '\n' by itself. Instead, prefix the '\n' character with a '%' character. This two-character sequence, "%\n", indicates that the system-dependant line terminator should be substituted at run-time. Thus, it might be better if the format string in the above examples was "(%5d, %6.2f, %#10x)%\n".

%\n is not a standard printf feature, but is an extension available only in Printf for Java. Because the Java programming environment is different from the C programming environment in so many different ways, you will find that Printf for Java adds many additional, useful features to C's printf API. Don't worry about compatibility, however; Printf for Java is backward compatible with the C's printf specification. For complete details, consult the Printf for Java Format String Specification.


I have shown only a very small sampling of the many ways in which the text-formatting features of Printf for Java can be used in Java programs to produce beautiful output. If your programs need to produce formatted text output, you should check out Printf for Java to see how helpful it can be.

©1998-2001 Sharkysoft. Comments on this article are welcome.