The versatile Formatter class in Java

When it comes to interpreting printf-style format strings, we can see that Java is not lacking in functionality. Developers often forget how powerful this class is.

Basic Usage

As we know, a formatter takes an format string and an argument list:

String name = "Bob";
String.format("Hi %s!", name); <- returns "Hi Bob!"
Note — the definition of String.format is the following (so you’ll see that we’re actually using Formatter all along).
public static String format(String format, Object... args) {
return new Formatter().format(format, args).toString();
}

Format specifiers — more control to you

In the above example, only %s to indicate a string. But the the formatter allows for more specifiers:

%[argument_index$][flags][width][.precision]conversion

argument_index — this means you can indicate the position of the argument. It’s good for repeating an argument without passing it several times in the argument list:

String.format("Hi $1$%s. Hi again $1$%s.", name);

Playing around with multiple arguments, we can also do:

String[] letters = {"a", "b", "c"};
String.format("%3$s %s %s %s", letters); <- returns "c a b c"
String.format("%s %<s %<s", letters); <- returns "a a a"

The ‘%<s’ as seen above allows us to use relative positioning, e.g. use the argument that came before.

conversion — we’ve already seen %s. Others include x (hexadecimal), F for ISO-8601 dates, and even currency formatting according to a locale like so:

double balance = 1234678.90;
StringBuilder sb = new StringBuilder();
new Formatter(sb, Locale.US).format("$ %(,.2f", balance);
System.out.println(sb);

The above prints out “$ 1,234,678.90”.

String.format("My Birthdate: %1$tb %1$te, %1$tY", 
new GregorianCalendar(1983, Calendar.NOVEMBER, 4));

The above returns “My Birthdate: Nov 4, 1983”.

flags — to do things like zero padding, left justification, leading spaces, enclosing negative numbers in parentheses. The latter can be shown by changing the balance variable (see two examples up) to a negative value.

width — this is to specify the minimum number of characters to be written to output. Here’s a neat printing of fictional salaries:

Map<String, Double> map = new HashMap<>();
map.put("Bob Hoskins", 1334.30);
map.put("Sue Ismyname", 960.14);
map.put("Jim Morrison", 810.63);
map.forEach((k, v) ->
System.out.println(String.format("%-20S $ %,.2f", k, v))
);

The output of which looks neat due to the first argument’s negative width:

Reference (this will be your next step): http://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html