String.format()... You May Be Doing It Wrong
Thursday, March 29, 2018 |If you’ve been working with Java for very long, you’ve probably had occasion to use
String.format()
. And, if you’re like me, you may very well have been doing it "wrong".
Let’s take a look at what was, for me, common usage, and how, maybe, you should be
doing it.
Let’s start by taking a look at a mildly complex — and highly contrived — usage:
1
2
3
String foo = String.format("one %s two %s three %s four %s five %s one again %s",
"1", "2", "3", "4", "5");
System.out.println(foo);
Other than being beyond ugly, can you spot the problem? Six format specifiers, and five
values. It compiles just fine, but blows up at runtime, so that’s no good. There are,
of course, other ways to build such a string. StringBuilder comes quickly to mind,
but there are times when a use of format()
makes more readable code than a series
of calls to append()
.
1
2
3
4
5
6
7
8
9
10
11
12
13
String foo2 = new StringBuilder("one ")
.append("1")
.append(" two ")
.append("2")
.append(" three ")
.append("3")
.append(" four ")
.append("4")
.append(" five ")
.append("5")
.append(" one again ")
.append("1")
.toString();
Not really a whole lot prettier, but the point here isn’t finding the prettiest way to write something like this. We’re trying to see how to use String.format() in a safer, more reliable way, so let’s get to it.
The key is the "argument index", which you can read more about here. Using the argument index, you can specify which value in the argument list goes with the format specifier in question. Using that, we could rewrite the first example like this:
1
2
3
String foo3 = String.format("one %1$s two %2$s three %3$s four %4$s five %5$s one again %1$s",
"1", "2", "3", "4", "5");
System.out.println(foo3);
This doesn’t solve the missing argument issue, but it does allow us to avoid repeating values. It’s not super obvious in this example, so let’s try an uglier one, one in which a particular value needs to be repeated many, many times:
1
2
String foo4 = String.format("one %1$s two %1$s three %1$s four %1$s five %1$s", "1");
System.out.println(foo4);
Six format specifiers, one value. Pretty fancy, eh?
So, if you find yourself needing to build a complicated string, especially with a large number of repeating values, argument indices are your friend. And don’t be too hard on yourself if this is new to you. I just learned it about too, so you’re in good… well… you have company. :)