Back to Blog
Java

Java String Format: Syntax and Practical Usage

java string format: Learn Java String.format syntax, specifiers, width, precision, argument indexes, locale handling, and when to choose it over concatenation.

String FormattingJava StringsFormatter APILocale HandlingStringBuilder
Diagram of a Java format string with percent specifiers mapping to argument values

Java string format, through the String.format() method, lets you build output from a template and a set of values. The first argument is the format string. The remaining arguments are values referenced by format specifiers. Each specifier begins with a percent sign and ends with a conversion character.

String message = String.format("Order %d shipped to %s", orderId, customerName);

The method delegates to the java.util.Formatter class, so the syntax is identical whether you call String.format() or instantiate a Formatter directly. That shared syntax is what makes the API worth learning once and reusing across projects.

The Format Specifier Syntax

A complete format specifier follows this structure:

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

Only the percent sign and the conversion character are required. Everything else is optional. The conversion character determines how the corresponding argument is interpreted. For example, %d expects an integral value, %f expects a floating-point value, and %s accepts any object and calls its toString() method.

String.format("%d", 42); // "42" String.format("%f", 3.14); // "3.140000" String.format("%s", "hello"); // "hello"

The Formatter class defines the full set of conversions. The most frequently used ones are %s for strings, %d for integers, %f for floating-point numbers, %x for hexadecimal, and %t for date and time values. Date and time conversions require a two-character sequence after the percent sign, such as %tY for a four-digit year.

Common Conversions and Their Behavior

ConversionArgument typeExample output
%sAny objectString.valueOf(arg)
%dbyte, short, int, long42
%ffloat, double3.140000
%xintegral types2a
%tYDate, Calendar, long2024

The %s conversion is the most flexible. It accepts any object and uses its toString() method. For arrays, toString() produces the identity-based representation such as [Ljava.lang.String;@1a2b3c, so Arrays.toString() is usually needed first. For custom classes, overriding toString() gives you control over what %s prints.

Controlling Width, Precision, and Alignment

Width sets the minimum number of characters in the output. If the formatted value is shorter, it is padded with spaces. Precision has different meanings depending on the conversion. For floating-point numbers, it sets the number of digits after the decimal point. For strings, it truncates the value to that many characters.

String.format("%10s", "abc"); // " abc" String.format("%.2f", 3.14159); // "3.14" String.format("%.3s", "abcdef"); // "abc"

The minus flag reverses the padding direction. %-10s produces a left-aligned value. The zero flag pads numeric values with zeros instead of spaces, which is common for fixed-width identifiers such as order numbers or transaction IDs.

String.format("%05d", 42); // "00042" String.format("%-10s", "abc"); // "abc "

Width and precision are independent. You can combine them, as in %10.2f, which produces a ten-character-wide field with two decimal places. The value is padded first, then rounded to the requested precision.

Working with Argument Indexes

By default, specifiers consume arguments in order. The first %s uses the first argument, the second %s uses the second, and so on. Explicit indexes let you reference arguments out of order or reuse the same argument multiple times.

String.format("%2$s has %1$d items", 5, "cart"); // "cart has 5 items"

The index is written as a number followed by a dollar sign immediately after the percent character. Reusing an argument avoids passing the same value twice and keeps the format string self-contained. This is particularly useful when the same value appears in multiple places, such as an ID that appears in both a label and a URL.

Mixing indexed and unindexed specifiers in the same format string is allowed but confusing. The unindexed specifiers continue from the last used index, which rarely produces the output you intend. Keep one style per format string.

Locale-Aware Formatting

String.format has an overload that accepts a Locale as the first argument. Without it, the default locale is used. This matters for numbers and dates, because the decimal separator, grouping character, and date layout vary by locale.

String.format(Locale.GERMANY, "%.2f", 1234.5); // "1234,50" String.format(Locale.US, "%.2f", 1234.5); // "1234.50"

A common production bug is relying on the default locale for output that is parsed elsewhere. If the output is consumed by another system, passing Locale.ROOT or an explicit locale keeps the format stable across environments. This is especially relevant for CSV exports, API responses, and log files that feed into monitoring tools.

Performance Considerations in Hot Paths

Each call to String.format creates a new Formatter instance internally. That involves object allocation and parsing of the format string. For occasional log messages or user-facing output, the cost is irrelevant. In a tight loop that runs thousands of times per request, the allocation overhead becomes measurable.

String concatenation with the + operator compiles to StringBuilder.append() calls. For simple cases with a few values, that is usually faster than String.format because no format parsing occurs. StringBuilder is the right choice when building a large string from many parts.

String.format earns its cost when the format itself is the point: alignment, padding, locale handling, and reusable format templates. A format string stored as a constant and applied to many argument sets is a legitimate use case. The parsing cost is paid once per call, so the benefit comes from readability and consistency, not raw throughput.

Common Mistakes and Their Symptoms

Passing the wrong argument type produces a java.util.IllegalFormatConversionException at runtime. For example, %d with a String argument fails immediately. This is a runtime failure, not a compile-time one, because the format string is only interpreted when the method is called.

Missing arguments cause java.util.MissingFormatArgumentException. This happens when the format string references more arguments than were passed. The exception message includes the format specifier that could not be satisfied, which makes the root cause straightforward to locate.

A less obvious failure is the default locale. Code that works on a developer machine can produce different output in production when the default locale differs. This appears as unexpected decimal separators or date formats. The fix is to pass an explicit locale, not to assume the environment is consistent.

Choosing Between String.format and Other Approaches

Use String.format when the output needs alignment, padding, locale-aware number formatting, or a reusable format template. Use plain concatenation or StringBuilder when assembling a string from a small number of values and none of those features are needed.

MessageFormat is a separate API that handles pluralization and named arguments, but it has different syntax and is primarily aimed at localization. String.format is the standard choice for general-purpose formatting because its syntax is compact and widely understood.

The decision is not about which is faster in isolation. It is about whether the format string adds clarity or maintenance value. A complex output built with dozens of concatenation operators is harder to read than the equivalent format string. Conversely, a one-off log line with two values does not benefit from the extra abstraction. Match the tool to the actual formatting requirements rather than applying the same approach everywhere.

java string format: Practical Usage and Code Examples | RYUSLOG DEV