Let's suppose that we have 10 numbers (integers and doubles) and we want them to be nicely formatted (have an indentation, alignment, and a number of decimals that sustain readability and usefulness) in a file.
In our first attempt, we wrote them to the file like so (no formatting was applied):
Path path = Paths.get("noformatter.txt");
try (BufferedWriter bw = Files.newBufferedWriter(path,
StandardCharsets.UTF_8, StandardOpenOption.CREATE,
StandardOpenOption.WRITE)) {
for (int i = 0; i < 10; i++) {
bw.write("| " + intValues[i] + " | " + doubleValues[i] + " | ");
bw.newLine();
}
}
The output of the preceding code is similar to what's shown on the left-hand side of the following diagram:
However, we want to obtain the result that's shown on the right-hand side of the preceding diagram. In order to solve this problem, we need to use the String.format() method. This method allows us to specify the format rules as a string that respects the following pattern:
%[flags][width][.precision]conversion-character
Now, let's take a look at what represents each component of this pattern:
- [flags] is optional and consists of standard approaches for modifying the output. Often, they are used for formatting integers and floating-point numbers.
- [width] is optional and sets the field width for our output (the minimum number of characters written to the output).
- [.precision] is optional and specifies the number of digits of precision for floating-point values (or the length of a substring to extract from a String).
- conversion-character is mandatory and tells us how the argument will be formatted. The most used conversion-characters are as follows:
- s: Used for formatting strings
- d: Used for formatting decimal integers
- f: Used for formatting floating-point numbers
- t: Used for formatting date/time values
With this knowledge of formatting rules, we can obtain what we want as follows (%6s is used for the integers while %.3f is used for the doubles):
Path path = Paths.get("withformatter.txt");
try (BufferedWriter bw = Files.newBufferedWriter(path,
StandardCharsets.UTF_8, StandardOpenOption.CREATE,
StandardOpenOption.WRITE)) {
for (int i = 0; i<10; i++) {
bw.write(String.format("| %6s | %.3f |",
intValues[i], doubleValues[i]));
bw.newLine();
}
}
Another solution can be provided via the Formatter class. This class is dedicated to format strings and uses the same formatting rules as String.format(). It has a format() method, which we can use to rewrite the preceding snippet of code:
Path path = Paths.get("withformatter.txt");
try (Formatter output = new Formatter(path.toFile())) {
for (int i = 0; i < 10; i++) {
output.format("| %6s | %.3f |%n", intValues[i], doubleValues[i]);
}
}
How about formatting only the integer's numbers?
Well, we can obtain this by applying a DecimalFormat and a string formatter, as follows:
Path path = Paths.get("withformatter.txt");
DecimalFormat formatter = new DecimalFormat("###,### bytes");
try (Formatter output = new Formatter(path.toFile())) {
for (int i = 0; i < 10; i++) {
output.format("%12s%n", formatter.format(intValues[i]));
}
}