StringBuilder & String Formatting
Strings in Java are immutable, which makes glueing lots of text together with + surprisingly wasteful. Meet StringBuilder for efficient text assembly, and printf / String.format for clean, aligned, professional output.
Learn StringBuilder & String Formatting in our free Java course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a…
Part of the free Java course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
A String can never be changed after it's created. When you write s = s + "!" , Java doesn't edit the old text — it builds a brand-new String and points s at it. The original is left untouched (and eventually garbage-collected).
💡 Analogy: A String is like a printed page — you can't erase a word on it. To "change" it you photocopy the page, write the new version, and throw the old copy away. Do that a million times in a loop and you've made a million photocopies.
This is usually fine. It only becomes a performance problem when you concatenate inside a large loop, where the cost grows quadratically.
StringBuilder is a mutable , growable buffer of characters. Instead of creating a new object on every change, append() writes into the same buffer — and it returns the builder itself, so calls can be chained.
Glueing values together with + gets ugly fast, and you can't easily control decimals or alignment. Format specifiers solve that. System.out.printf prints directly; String.format returns the text as a value.
Reorder these lines so they build a CSV-style line "a,b,c" with a StringBuilder and print it.
Why: The builder must be created first, then appended to, before toString() can extract the finished text. (The line variable and the printed sb.toString() are equivalent — you'd normally print line .) Output: a,b,c .
abc — unchanged! Strings are immutable, so toUpperCase() returns a new String that is thrown away. You must capture it: s = s.toUpperCase(); .
03.50 . Two decimal places, total width 5, zero-padded — "3.50" is 4 chars, so one leading zero fills it to 5.
avaJ . reverse() mutates the builder in place, and printing it implicitly calls toString() .
You now understand why Strings are immutable, when to reach for StringBuilder , and how to produce polished output with printf and String.format — including decimals, padding, alignment, and grouping.
Next up: ArrayList — a resizable, dynamic list that grows and shrinks as you add and remove items.
Practice quiz
What does this print? StringBuilder sb = new StringBuilder("Java"); sb.reverse(); System.out.println(sb);
- Java
- JAVA
- avaJ
- java
Answer: avaJ. reverse() mutates the builder in place to avaJ, and printing it implicitly calls toString().
Why are Java Strings immutable a problem when concatenating in a large loop?
- Each + creates a new String object, making the loop O(n squared) work
- The loop never terminates
- Strings cannot be concatenated at all
- It causes a compile error
Answer: Each + creates a new String object, making the loop O(n squared) work. Because Strings are immutable, each + allocates a brand-new object. In a large loop that quadratic allocation is genuinely slow - StringBuilder fixes it.
What does new StringBuilder().append("a").append(1).append("b").toString() produce?
- "ab"
- "a b"
- "1ab"
- "a1b"
Answer: "a1b". append accepts any value and adds it to the end in order: "a", then 1, then "b" gives "a1b". Calls chain because append returns the builder.
What does System.out.printf("%05.2f%n", 3.5) print?
- 3.50
- 03.50
- 3.5
- 003.5
Answer: 03.50. Two decimal places gives "3.50" (4 chars); width 5 zero-padded adds one leading zero: 03.50.
What is the difference between System.out.printf and String.format?
- printf prints to the console; String.format returns the formatted String as a value
- They use different specifiers
- String.format is faster
- printf returns the String
Answer: printf prints to the console; String.format returns the formatted String as a value. Both use identical specifiers, but printf prints directly while String.format builds and returns the text so you can store or pass it.
What does this print? String s = "abc"; s.toUpperCase(); System.out.println(s);
- ABC
- Abc
- abc
- It throws an exception
Answer: abc. Strings are immutable: toUpperCase() returns a NEW String that is discarded. You must capture it with s = s.toUpperCase().
Which specifier prints a literal percent sign in a format string?
- %
- %%
- \%
- %p
Answer: %%. A lone % starts a specifier, so you write %% to print one literal percent sign.
What does String.format("[%03d]", 9) return?
%03d zero-pads the number to 3 digits, producing "[009]".
When should you reach for StringBuilder instead of +?
- For every single concatenation, always
- When building a string piece by piece, especially inside a loop
- Never - + is always better
- Only for joining exactly two literals
Answer: When building a string piece by piece, especially inside a loop. Use StringBuilder when assembling text in a loop. For a one-off join of two or three literals, plain + is fine and more readable.
Which printf specifier should you prefer for a portable newline?
- %n
- %l
Answer: %n. %n produces a platform-independent newline inside printf, preferred over so output uses the correct line ending on every OS.