FAQ: A note on printf

Heidi Newton

Some students have been confused by format strings. You may be getting errors such as "java.util.IllegalFormatConversionException:". If you haven't already, go back and read the notes in the lecture notes.

Basically, a format string is a string with "holes" in it that are represented using a % sign along with a letter such as "d", "f", or "s". The format string is then followed with a list of variables to use to "fill" the holes.

Like the lecture notes say, %d is a hole for an integer, %s is a hole for a string, and %f is a hole for a double. Some students have been putting %d for a double, thinking that d means double, when in actual fact it means integer. (If you are interested, the reason that "d" is for integer is because it stands for decimal integer, and "f" is for double because a double is actually a floating point number)

For example, imagine we have a very simple method that prints how many of an item there are left of an item that is on special in a shop, the price of each item, and the day the sale goes on until. This is a part of that method.
String item = "Coke cans"; 
   String saleEnds = "Thursday"; 
   int numLeft = 55; 
   double price = 1.10;
   UI.printf("There are %d %s left in the shop, on sale for $%f each until %s", numLeft, item, price, saleEnds); 

There are 4 holes in this string. %d, %s, %f, %s. Each of these holes has to be filled, and is filled in order with the parameters that follow. So the %d hole gets filled with the value of numLeft, the first %s gets the value of item, %f gets the value of price, and the second %s gets the value of saleEnds. It is really important to remember that:
  • the parameters are put into the holes IN ORDER. If your first hole is an int and your second is a String, but you list the string before the int in your parameters, it won't know to swap them around based on the types. It will just do exactly as you told it and crash.
  • the $ sign is NOT part of a hole: it is there so that a $ sign is put in front of the money amount. If you don't put it, it won't appear as Java does not know that the value is money.

In this example, I simply declared variables and put values into them, just above the printf call. In practice though, the expressions you use to fill the holes of the formatted string could be parameters, or have values assigned to them in a different way to simply putting direct values in like I did.

If you are getting the "java.util.IllegalFormatConversionException:" error, this simply means that one of the values you are trying to fill a hole with is not the correct type for the hole. For example, you might be trying to put an integer into a hole that is for a double, or a string into a hole that was for an integer. Double check the types of the holes in the format string, and the types of the variables you are using to fill the holes, and the order you have listed the variables to fill the holes with in.

One other problem is that this would print

There are 55 Coke cans left in the shop, on sale for $1.100000 each until Thursday

When we write money values, we don't want to have so many 0's attached to the end of them! This is where the extra information you can attach to a hole for a double comes in handy. Instead of what was written above, we could instead use
UI.printf("There are %d %s left in the shop, on sale for $%0.2f each until %s", numLeft, item, price, saleEnds);
Note that the "%f" hole has changed to %0.2f. The 0 means use 0 padding (I'm not going to provide help on the padding here, as I don't think it is too important yet, basically it is nice for lining things up), and the 2 means use 2 decimal places. This is explained in the lecture notes as well.

A format string is a string value. Typically it is a string literal, just like all other string literals it is in double quotes. Make sure you only have one string literal when using printf; if you have +'s to connect strings together in printf, you are probably doing something wrong. Also, do not put values into the string in the "println" way in a printf call, be consistent and put all values into the string by making holes and putting the values to fill them after the string. For example, this is NOT good style, and we don't want to see anything like this!!!
UI.printf("There are " + numLeft + " %s left in the shop, on sale for $%f each until " + saleEnds, item, price);

One more issue I've seen a few times is when people do things like this (if you are finding that only parts of your output are appearing, this might very well be the reason!!)
UI.printf("Dear %s,", name, "you have been selected for a special offer on %s", product, "buy 1 and get 10 free if you purchase by %s", date);
This code really doesn't make much sense, as printf is supposed to take a format string (a string with "holes" in it) for the first parameter to printf, and then the rest of the parameters given to it are supposed to be the values to use to fill the "holes".

In this case, it will see the format string is "Dear %s". It will then look for values to fill the holes, and seeing as there is one, it will take the next parameter, which is "name", and put it into the format string. Because there were no more holes in the format string, it will just ignore all those other parameters you have given it (parameters are separated by commas, so it just treats everything else as more parameters).

As a result, the output will be (assuming name is "Heidi")
Dear Heidi,
And the rest will be lost.

The correct thing to put in this example would be
UI.printf("Dear %s, you have been selected for a special offer on %s buy 1 and get 10 free if you purchase by %s", name, product, date); 
Note that the format string is the first parameter, containing 3 holes, and then after that, the next 3 parameters are what to use to fill the holes.