Java String Formatting: String.format, printf, and formatted()
Java provides several ways to format strings: String.format() returns a formatted string, System.out.printf() prints it directly, and the instance method formatted() (Java 15+) makes format chains cleaner. Format specifiers control width, precision, alignment, and number representation. Locale-aware formatting ensures correct output across different regions.
Contents
Common Format Specifiers
String.format()printf()%stoString()%d%f%n\n%b%c%x%%%e%o
// String.format(format, args...) โ returns a String
// System.out.printf(format, args...) โ prints, no newline
// System.out.println(String.format(...)) โ print with newline
// Common specifiers:
// %s โ String (or toString() of any Object)
// %d โ decimal integer (int, long)
// %f โ floating point (double)
// %e โ scientific notation
// %b โ boolean
// %c โ character
// %n โ platform newline (prefer over \n for portability)
// %x โ hexadecimal integer
// %o โ octal integer
// %% โ literal percent sign
String name = "Alice";
int age = 30;
double score = 95.678;
String msg = String.format("Name: %s, Age: %d, Score: %.2f", name, age, score);
System.out.println(msg); // Name: Alice, Age: 30, Score: 95.68
System.out.printf("Hello, %s! You scored %d points.%n", name, (int)score);
// %b โ boolean
boolean active = true;
System.out.printf("Active: %b%n", active); // Active: true
System.out.printf("Active: %b%n", null); // Active: false (null โ false)
// %x โ hexadecimal
System.out.printf("0x%X%n", 255); // 0xFF
System.out.printf("0x%08x%n", 255); // 0x000000ff (zero-padded to 8)
Formatting Numbers
%.2f%,d%08d%e%.2eNumberFormatLocaleString.format()
double pi = Math.PI; // 3.141592653589793
// .Nf โ N decimal places
System.out.printf("%.0f%n", pi); // 3
System.out.printf("%.2f%n", pi); // 3.14
System.out.printf("%.5f%n", pi); // 3.14159
// %e โ scientific notation
System.out.printf("%e%n", 1234567.89); // 1.234568e+06
System.out.printf("%.2e%n", 1234567.89); // 1.23e+06
// %,d โ thousands separator (locale-dependent)
System.out.printf("%,d%n", 1_000_000); // 1,000,000
System.out.printf("%,.2f%n", 1_234_567.89); // 1,234,567.89
// %+d โ force sign
System.out.printf("%+d, %+d%n", 42, -42); // +42, -42
// Formatting with java.text.NumberFormat (locale-aware)
NumberFormat nf = NumberFormat.getInstance(Locale.GERMANY);
System.out.println(nf.format(1234567.89)); // 1.234.567,89 (German locale)
NumberFormat currency = NumberFormat.getCurrencyInstance(Locale.US);
System.out.println(currency.format(1234.56)); // $1,234.56
Width, Precision, and Alignment
Width is the minimum field width: the formatted value is padded to at least that many characters. Numbers are right-aligned by default; the -%-10s+%+d%.5s%8.2f%08d
// Width โ minimum field width (right-aligned by default)
System.out.printf("[%10s]%n", "hi"); // [ hi]
System.out.printf("[%10d]%n", 42); // [ 42]
// Left-align with -
System.out.printf("[%-10s]%n", "hi"); // [hi ]
System.out.printf("[%-10d]%n", 42); // [42 ]
// Zero-pad numbers
System.out.printf("[%010d]%n", 42); // [0000000042]
System.out.printf("[%010.2f]%n", 3.14); // [0000003.14]
// Width and precision together
System.out.printf("[%10.2f]%n", 3.14159); // [ 3.14] (width 10, 2 decimals)
// Building a table
String fmt = "%-20s %5d %8.2f%n";
System.out.printf(fmt, "Widget", 150, 4.99);
System.out.printf(fmt, "Gadget", 1200, 12.50);
System.out.printf(fmt, "Sprocket", 35, 0.89);
// Widget 150 4.99
// Gadget 1200 12.50
// Sprocket 35 0.89
// Argument index โ reuse an argument
System.out.printf("%1$s loves %1$s.%n", "Java"); // Java loves Java.
formatted(): Java 15+
String.formatted(args)String.format(this, args)"Hello, %s!".formatted(name)String.format()String.format(Locale, format, args)
// formatted() is an instance method on String โ same as String.format() but cleaner in chains
String msg = "Name: %s, score: %.1f".formatted("Bob", 88.5);
System.out.println(msg); // Name: Bob, score: 88.5
// Useful with text blocks (Java 15+) for multi-line templates
String json = """
{
"name": "%s",
"age": %d,
"score": %.2f
}
""".formatted("Alice", 30, 95.67);
System.out.println(json);
// Chaining in stream pipelines
List.of("Alice", "Bob", "Charlie")
.stream()
.map(name -> "Hello, %s!".formatted(name))
.forEach(System.out::println);
// formatted() vs String.format() โ functionally identical
String a = String.format("Value: %d", 42); // traditional
String b = "Value: %d".formatted(42); // Java 15+, more readable
Locale-Aware Formatting
When no LocaleString.format()Locale.getDefault()%.2f1234,501234.50Locale.USLocale.ROOT
// String.format with Locale โ avoid locale-sensitive defaults
String us = String.format(Locale.US, "%.2f", 1234.5); // "1234.50"
String de = String.format(Locale.GERMANY, "%.2f", 1234.5); // "1234,50"
String fr = String.format(Locale.FRANCE, "%.2f", 1234.5); // "1 234,50"
// Formatted output using Locale
System.out.printf(Locale.US, "%,.2f%n", 1_234_567.89); // 1,234,567.89
// Dates with DateTimeFormatter (modern approach)
LocalDate date = LocalDate.of(2025, 3, 15);
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("MMMM d, yyyy", Locale.US);
System.out.println(date.format(fmt)); // March 15, 2025
DateTimeFormatter deFmt = DateTimeFormatter.ofPattern("d. MMMM yyyy", Locale.GERMANY);
System.out.println(date.format(deFmt)); // 15. Mรคrz 2025
// MessageFormat โ handles plurals and locale-sensitive messages
String pattern = "There {0,choice,0#are no files|1#is one file|1<are {0} files}.";
System.out.println(MessageFormat.format(pattern, 0)); // There are no files.
System.out.println(MessageFormat.format(pattern, 1)); // There is one file.
System.out.println(MessageFormat.format(pattern, 5)); // There are 5 files.
LocaleString.format()