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.