Java String Formatting and StringBuilder

Produce neat output with printf and String.format, build long strings efficiently with StringBuilder, and write multi-line text with text blocks.

Lesson 17 of 127Beginner18 min read

Joining text with + works fine for short messages, but it quickly gets messy. Showing a price with exactly two decimal places, lining up a table of results, or building a long piece of text inside a loop all need better tools.

Java has three that cover almost every case. Format strings, used by printf and String.format, describe exactly how each value should look: how many decimal places, how wide, aligned left or right. StringBuilder builds long strings piece by piece efficiently, without creating a new string at every step. And text blocks let you write multi-line text, such as an email template or some JSON, just as it should appear.

In this lesson you'll learn the format specifiers you'll use most, build a neatly aligned receipt, assemble strings in a loop with StringBuilder, and write readable multi-line text.

printf and String.format

Both take a format string containing placeholders, followed by the values to put in them:

Java
System.out.printf("%s is %d years old%n", "Ada", 36);
String line = String.format("Total: £%.2f", 12.5);   // "Total: £12.50"
  • printf prints the result straight away; String.format returns it as a String.
  • %s is for any value as text, %d for whole numbers and %f for decimals.
  • %n is a new line that works on every operating system. printf doesn't add one by itself.
  • Java 15 and later also let you write "Total: £%.2f".formatted(12.5).

Format specifiers

SpecifierMeaningExampleResult
%.2f2 decimal places12.512.50
%,dThousands separator12345671,234,567
%8sRight-align in 8 characters"tea" tea
%-8sLeft-align in 8 characters"tea"tea
%05dPad with zeros to 5 digits4200042
%8.2fWidth 8, 2 decimals3.14159 3.14
%%A literal percent sign%

The pattern is always %, then options such as -, 0 or ,, then a width, then . and precision, then the type letter.

StringBuilder

Java strings are immutable: every + creates a brand new String. Inside a loop that runs thousands of times, that's a lot of wasted work. A StringBuilder is a growable piece of text you can change in place:

Java
StringBuilder sb = new StringBuilder();
sb.append("Hello").append(", ").append("world");
sb.insert(0, ">> ");
String result = sb.toString();   // ">> Hello, world"

Useful methods include append(), insert(), reverse(), deleteCharAt(), setLength() and length(). Call toString() at the end to get an ordinary String.

String.join and text blocks

String.join(", ", list) joins the items of a list or array with a separator, which is much simpler than a loop when you just need "a, b, c".

A text block (Java 15 and later) starts with three double quotes and a new line, and ends with three double quotes:

Java
String email = """
    Hello %s,
    Your order #%d has shipped.
    """.formatted("Sam", 1042);

Java removes the shared indentation from every line, keeps the line breaks, and lets you use " inside without escaping. Text blocks are ideal for SQL queries, JSON, HTML and message templates.

Choosing the right tool for building text

Each way of building text has a job it does best:

TaskBest toolExample
A short message from two or three values+"Hi " + name
Fixed decimal places, widths or alignmentprintf / String.format"%.2f"
Text built up inside a loopStringBuildersb.append(line)
Items with a separator between themString.join"a, b, c"
Several lines of fixed texta text block"""..."""

Mixing them is normal: a loop can append formatted lines to a StringBuilder, sb.append(String.format("%-10s%6.2f%n", item, price)), and the result is printed once at the end.

Format errors to recognise

Format strings are checked when the program runs, not when it compiles, so mistakes show up as exceptions:

  • IllegalFormatConversionException: the specifier doesn't fit the value, such as %d with a double. Use %f for decimals and %d for whole numbers; %s accepts anything.
  • MissingFormatArgumentException: there are more placeholders than values, such as "%s and %s" with one argument.
  • UnknownFormatConversionException: a stray % that isn't a specifier. Write %% for a literal percent sign.

Extra arguments, on the other hand, are silently ignored, so count your placeholders when output looks incomplete.

Java String Formatting Syntax

Formatting tools

System.out.printf("%-10s%6.2f%n", name, price);
String s = String.format("%,d items", count);
String t = "%s: %d".formatted(label, value);

StringBuilder sb = new StringBuilder();
sb.append(x).append(y);
String out = sb.toString();

String.join(", ", list);
String block = """
    line one
    line two
    """;

Java String Formatting Summary

  • printf prints formatted text; String.format and formatted() return it.
  • %s, %d and %f are text, whole numbers and decimals; %n is a new line.
  • Width, alignment, precision and flags like , and 0 control the layout.
  • StringBuilder builds long strings efficiently; call toString() at the end.
  • String.join joins items with a separator; text blocks hold multi-line text.

Java String Formatting Examples

Each example shows the code, the output it produces and what each part does.

Example 1

A neatly aligned receipt

Java
public class Main {
    public static void main(String[] args) {
        String[] items = {"Coffee", "Bagel", "Orange juice"};
        int[] qty = {2, 1, 3};
        double[] price = {2.80, 3.25, 1.90};

        System.out.printf("%-14s%4s%9s%n", "Item", "Qty", "Total");
        double total = 0;
        for (int i = 0; i < items.length; i++) {
            double line = qty[i] * price[i];
            total += line;
            System.out.printf("%-14s%4d%9.2f%n", items[i], qty[i], line);
        }
        System.out.printf("%-18s%9.2f%n", "TOTAL", total);
    }
}
Output
Item           Qty    Total
Coffee           2     5.60
Bagel            1     3.25
Orange juice     3     5.70
TOTAL                 14.55
Line-by-line explanation
  1. Line 7The heading uses the same widths as the rows, so the columns line up.
  2. Line 12Name left-aligned in 14, quantity right-aligned in 4, total in 9 with 2 decimals.
  3. Line 14TOTAL takes 18 characters, the width of the first two columns together.
Example 2

Building a string with StringBuilder

Java
public class Main {
    public static void main(String[] args) {
        StringBuilder bar = new StringBuilder();
        int[] scores = {3, 7, 5};
        String[] names = {"Ana", "Ben", "Cy"};

        for (int i = 0; i < scores.length; i++) {
            bar.append(String.format("%-4s", names[i]));
            bar.append("#".repeat(scores[i]));
            bar.append(" ").append(scores[i]).append('\n');
        }
        System.out.print(bar);

        StringBuilder word = new StringBuilder("level");
        System.out.println(word.reverse() + " is a palindrome? "
                + word.toString().equals("level"));
    }
}
Output
Ana ### 3
Ben ####### 7
Cy  ##### 5
level is a palindrome? true
Line-by-line explanation
  1. Line 8Pad each name to 4 characters so the bars start in the same column.
  2. Line 9repeat() makes a bar of # characters as long as the score.
  3. Line 10append() calls can be chained because each returns the builder itself.
  4. Lines 14 to 15reverse() changes the builder in place; "level" reads the same backwards.
Example 3

Joining and text blocks

Java
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> toppings = List.of("cheese", "basil", "olives");
        String list = String.join(", ", toppings);

        String message = """
            Order #%05d
            Pizza with: %s
            Price: £%,.2f
            """.formatted(42, list, 1250.5);
        System.out.print(message);
    }
}
Output
Order #00042
Pizza with: cheese, basil, olives
Price: £1,250.50
Line-by-line explanation
  1. Line 6join puts ", " between the items, with none at the end.
  2. Lines 8 to 12A text block keeps the line breaks; the shared indentation is removed.
  3. Line 9%05d pads the order number with zeros.
  4. Line 11%,.2f combines a thousands separator with two decimals.

Common Java String Formatting Mistakes

Forgetting %n with printf

Don't
System.out.printf("Total: %.2f", total);
System.out.printf("Tax: %.2f", tax);     // both on one line
Do
System.out.printf("Total: %.2f%n", total);
System.out.printf("Tax: %.2f%n", tax);

The wrong specifier for the type

Don't
System.out.printf("%d%n", 3.5);    // IllegalFormatConversionException
Do
System.out.printf("%.1f%n", 3.5);

%d is only for whole numbers; use %f for doubles.

Building strings with + in a big loop

Don't
String csv = "";
for (int i = 0; i < 10000; i++) {
    csv += i + ",";          // creates 10,000 new strings
}
Do
StringBuilder csv = new StringBuilder();
for (int i = 0; i < 10000; i++) {
    csv.append(i).append(',');
}

Java String Formatting in Real Projects

Formatting in real applications

Command-line tools and logs use printf-style formatting for aligned columns, invoices and receipts format money with two decimals and separators, and report generators build large documents with StringBuilder. Text blocks have become the standard way to embed SQL queries and JSON test data in Java code, because they look exactly like the real thing.

Java String Formatting FAQ

What is the difference between printf and println in Java?

println prints a value as it is and then moves to a new line. printf fills a format string with values, giving you control over decimal places, width and alignment, and doesn't add a new line unless you include %n.

How do I round a double to two decimal places in Java?

For display, use String.format("%.2f", value) or printf, which round to two places and keep trailing zeros, so 12.5 shows as 12.50. For calculations, especially with money, use BigDecimal with setScale(2, RoundingMode.HALF_UP) rather than rounding a double.

How do I format a number as currency?

NumberFormat.getCurrencyInstance(Locale.UK).format(1234.5) gives £1,234.50, and Locale.US gives $1,234.50. The locale chooses the symbol, the separators and the position of the symbol, which is safer than adding a currency sign by hand when your program serves several countries.

Should I use %n or \n in printf?

Use %n in format strings. It writes the correct line ending for the operating system the program runs on. \n always writes a single line-feed character, which is fine on Linux and macOS and usually fine on Windows, but %n is the convention in Java formatting code.

How do I pad a string or a number in Java?

Use a width in the specifier: %5s pads text on the left to five characters, %-5s pads on the right, and %05d pads a whole number with leading zeros. Zero padding only works for numbers. For text, "ab".repeat(n) or a loop can build custom padding.

Java String Formatting Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Complete the format so the price shows two decimal places.

System.out.printf("£%%n", 4.5);
Predict the outputeasy

What does this print?

System.out.println(String.format("%,d", 2500000));
Predict the outputmedium

What does this print?

System.out.println("[" + String.format("%-5s", "ab") + "]");
Multiple choicemedium

Why use StringBuilder inside a long loop?

Predict the outputhard

What does this print?

StringBuilder sb = new StringBuilder("abc");
sb.append("d").insert(0, "x").reverse();
System.out.println(sb);

Java String Formatting Quiz

5 questions to check what you learned.

  1. Which specifier is for a whole number?

    • %s
    • %f
    • %n
    • %d
  2. What's the difference between printf and String.format?

    • There's none
    • String.format only works with numbers
    • printf prints immediately; String.format returns a String
    • printf can't use %d
  3. What does %05d do to the number 7?

    • 7.00000
    • 00007
    • 70000
    • 5
  4. How do you print a percent sign in a format string?

    • \%
    • %%
    • %p
    • "%"
  5. What does a text block do with the indentation shared by all its lines?

    • Keeps it
    • Converts it to tabs
    • Causes a compile error
    • Removes it