How to format a Java String in Java 25

Java's Formatter syntax still provides a compact way to build formatted Strings, but Java 25 gives small programs a cleaner way to display the result.

The new java.lang.IO class provides basic console output through IO.print() and IO.println(). Combine that with String.formatted() and you can replace many older System.out.printf() examples with simpler Java 25 code.

For Strings, the two most important conversion specifiers are:

  • %s to format text while preserving its normal case;
  • %S to format the result in uppercase.

Here's a compact Java 25 example:

void main() {
    var name = "Cameron";
    var site = "Tss";

    IO.println(
        "I like the articles %s writes on %S."
            .formatted(name, site)
    );
}

The result is:

I like the articles Cameron writes on TSS.

This uses a Java 25 compact source file with void main(), so a small tutorial program no longer needs an explicit class declaration or public static void main(String[] args).

Java String formatting rules

For everyday String formatting, remember these rules:

  1. Use %s to insert a String or the String representation of an object.
  2. Use %S to uppercase the formatted result.
  3. Add a number before s to specify a minimum field width.
  4. Use - to left-align text within that field.
  5. Use a precision such as %.5s when you intentionally want to limit the maximum number of characters displayed.

When using IO.println(), you normally do not need %n at the end of the format String because println() already writes the line separator.

%s vs. %S in Java

The lowercase %s conversion keeps the normal String representation:

void main() {
    IO.println("Hello, %s".formatted("Cameron"));
}
{% highlight text %} Hello, Cameron {% endhighlight %} {% raw %}

Uppercase %S converts the formatted result to uppercase:

void main() {
    IO.println("Site: %S".formatted("Tss"));
}
{% highlight text %} Site: TSS {% endhighlight %} {% raw %}

What happened to System.out.printf?

System.out.printf() is still valid Java 25 and remains useful when direct formatted output is exactly what you want:

System.out.printf(
    "I like the articles %s writes on %S.%n",
    name,
    site
);

However, IO does not provide an IO.printf() method. A modern Java 25 alternative is to build the formatted String first and then print it:

IO.println(
    "I like the articles %s writes on %S."
        .formatted(name, site)
);

This approach cleanly separates formatting from output.

String.formatted vs. String concatenation

String concatenation is perfectly reasonable for small expressions:

void main() {
    var name = "Cameron";
    var site = "Tss";

    IO.println(
        "I like the articles " + name +
        " writes on " + site + "."
    );
}

But formatting placeholders are often easier to read when the sentence contains several inserted values:

void main() {
    var name = "Cameron";
    var site = "Tss";

    IO.println(
        "I like the articles %s writes on %S."
            .formatted(name, site)
    );
}

For SQL, JPQL and other long structured Strings, text blocks are often an even better option than either concatenation or a giant format String.

Java String Formatter syntax

The general String conversion syntax is:

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

Common String patterns include:

Pattern Meaning
%sFormat the value as a String.
%SFormat and uppercase the result.
%20sUse a minimum width of 20 and right-align.
%-20sUse a minimum width of 20 and left-align.
%.5sDisplay no more than five characters.
%-10.5sDisplay at most five characters in a left-aligned field of width 10.

Right-align String output

A width specifier creates a field with at least that many characters. Strings are right-aligned by default:

void main() {
    IO.println("|%10s|".formatted("Java"));
}
{% highlight text %} | Java| {% endhighlight %} {% raw %}

Left-align String output

Add the - flag to left-align the String:

void main() {
    IO.println("|%-10s|".formatted("Java"));
}
{% highlight text %} |Java | {% endhighlight %} {% raw %}

Limit the number of displayed characters

String precision specifies the maximum number of characters that may be written:

void main() {
    IO.println("%.5s".formatted("JavaScript"));
}
{% highlight text %} JavaS {% endhighlight %} {% raw %}

This is useful when fixed-width output must prevent unexpectedly long Strings from breaking the layout.

Use explicit Locale with %S when case rules matter

Uppercase formatting is locale-sensitive. For deterministic locale-specific formatting, use String.format() and provide the desired Locale explicitly:

void main() {
    var output = String.format(
        Locale.US,
        "Site: %S",
        "Tss"
    );

    IO.println(output);
}

Compact source files automatically import public top-level classes from packages exported by java.base, so this Java 25 example can use Locale without an explicit import.

Create a formatted table with Java 25 IO

Field width becomes particularly useful when creating aligned text tables.

void main() {
    IO.println("--------------------------------");
    IO.println(" Java's Primitive Types");
    IO.println("--------------------------------");
    IO.println(
        "| %-10s | %-8s | %4s |"
            .formatted("CATEGORY", "NAME", "BITS")
    );
    IO.println("--------------------------------");

    IO.println(
        "| %-10s | %-8s | %4s |"
            .formatted("Floating", "double", "64")
    );
    IO.println(
        "| %-10s | %-8s | %4s |"
            .formatted("Floating", "float", "32")
    );
    IO.println(
        "| %-10s | %-8s | %4s |"
            .formatted("Integral", "long", "64")
    );
    IO.println(
        "| %-10s | %-8s | %4s |"
            .formatted("Integral", "int", "32")
    );
    IO.println(
        "| %-10s | %-8s | %4s |"
            .formatted("Integral", "char", "16")
    );
    IO.println(
        "| %-10s | %-8s | %4s |"
            .formatted("Integral", "short", "16")
    );
    IO.println(
        "| %-10s | %-8s | %4s |"
            .formatted("Integral", "byte", "8")
    );
    IO.println(
        "| %-10s | %-8s | %4s |"
            .formatted("Boolean", "boolean", "1")
    );

    IO.println("--------------------------------");
}

The formatted output looks like this:

--------------------------------
 Java's Primitive Types
--------------------------------
| CATEGORY   | NAME     | BITS |
--------------------------------
| Floating   | double   |   64 |
| Floating   | float    |   32 |
| Integral   | long     |   64 |
| Integral   | int      |   32 |
| Integral   | char     |   16 |
| Integral   | short    |   16 |
| Integral   | byte     |    8 |
| Boolean    | boolean  |    1 |
--------------------------------
final printf table

Field width makes Java String formatting useful for console tables and reports.

A more maintainable Java 25 table example

If the data is repetitive, move the rows into a small record and use a loop rather than repeating the formatting call:

record Primitive(
    String category,
    String name,
    int bits
) {}

void main() {
    var types = List.of(
        new Primitive("Floating", "double", 64),
        new Primitive("Floating", "float", 32),
        new Primitive("Integral", "long", 64),
        new Primitive("Integral", "int", 32),
        new Primitive("Integral", "char", 16),
        new Primitive("Integral", "short", 16),
        new Primitive("Integral", "byte", 8),
        new Primitive("Boolean", "boolean", 1)
    );

    IO.println(
        "| %-10s | %-8s | %4s |"
            .formatted("CATEGORY", "NAME", "BITS")
    );

    for (var type : types) {
        IO.println(
            "| %-10s | %-8s | %4d |".formatted(
                type.category(),
                type.name(),
                type.bits()
            )
        );
    }
}

This version is a better demonstration of modern Java because the data is modeled separately from the display logic.

Use text blocks for multi-line templates

Formatter-style placeholders also work well inside text blocks. For example:

void main() {
    var name = "Cameron";
    var language = "Java 25";

    var message = """
        Developer: %s
        Language:  %s
        Status:    ready
        """.formatted(name, language);

    IO.print(message);
}

This is often much easier to maintain than building a multi-line String with concatenation or repeated newline escapes.

Run the Java 25 compact source file

Save a compact program as StringFormat.java:

void main() {
    var name = "Cameron";
    IO.println("Hello, %s!".formatted(name));
}

Run it directly:

java StringFormat.java

Or compile and run it normally:

javac StringFormat.java
java StringFormat

Java 25 String formatting cheat sheet

Goal Example
Insert a String IO.println("Hello %s".formatted(name));
Uppercase formatted String IO.println("%S".formatted(name));
Right-align to width 10 IO.println("%10s".formatted(name));
Left-align to width 10 IO.println("%-10s".formatted(name));
Limit to five characters IO.println("%.5s".formatted(name));

For modern Java 25 tutorials, the combination of String.formatted(), compact source files and IO.println() keeps String formatting examples concise without giving up the familiar power of Java's Formatter syntax.