๐Ÿ”ค Strings & Text ยท Beginner

StringBuilder vs StringBuffer in Java

StringBuffer is synchronized and legacy.

๐Ÿงฉ The mysteryJava has two classes that do exactly the same job with exactly the same methods. One is your everyday tool; the other mostly lives in old code. What separates them is one invisible word.

Twins with one difference

StringBuffer is the original (Java 1.0): a mutable string where **every method is synchronized**. StringBuilder arrived in Java 5 with the same API but no synchronization โ€” so it's faster.

var b1 = new StringBuffer("ab");   // locks
var b2 = new StringBuilder("ab");  // no locks
๐Ÿ”ฎ Predict it

Same tricks, older dog

StringBuffer has the same methods as StringBuilder. What prints?

var buf = new StringBuffer("12");
buf.append('3').append(4).reverse();
System.out.println(buf);
  1. 1234
  2. 4321
  3. 34
Show the answer

4321. append('3') and append(4) give "1234", then reverse() flips it. Same chaining, same behavior as StringBuilder.

What synchronized buys you

A synchronized method lets only one thread at a time run it on that object. Safe for sharing โ€” but taking the lock costs time on every call, even with a single thread. And builders are almost always local to one method, used by one thread.

๐Ÿค” Think first

Is a chain atomic?

Two threads share a StringBuffer and each runs buf.append("[").append(id).append("]"). Is every [id] guaranteed to appear unbroken?

Think about it, then reveal the answer

No. Each append call is atomic on its own, but a chain is three separate calls โ€” another thread can slip its append in between. Synchronized methods protect single calls, not sequences. You'd need one explicit lock around the whole chain.

โš ๏ธ The trap

Sharing a StringBuilder

StringBuilder has no locking at all. If two threads append to the same builder at once, they race on its internal buffer: text can get corrupted or an exception can be thrown. The rule: keep each builder thread-confined (local to one method), or synchronize externally.

The cheat sheet

String: immutable text. StringBuilder: mutable, not thread-safe, fast โ€” the default for building text. StringBuffer: mutable, synchronized, legacy. **+= in a loop**: a new String copy every iteration. Building a message inside one method? StringBuilder, every time.

๐Ÿ’ผ In the real world

In real projects

Code reviews often swap StringBuffer for StringBuilder in local code โ€” free speed. You'll still meet StringBuffer in old APIs: Matcher.appendReplacement accepted only a StringBuffer until Java 9 added a StringBuilder overload.

Key takeaways

  1. StringBuffer: synchronized, legacy
  2. StringBuilder: not synchronized, faster, preferred
  3. Same methods: append, insert, reverse, delete...
  4. Synchronized methods do not make a sequence of calls atomic
๐Ÿคฏ Did you know?

StringBuilder's own Javadoc says it was designed as a drop-in replacement for StringBuffer "in places where the string buffer was being used by a single thread (as is generally the case)" โ€” the locks were usually pure overhead.

Practice questions

What does this print?

var buf = new StringBuffer("ab");
buf.append(1).append('c').reverse();
System.out.println(buf);
  1. ab1c
  2. c1ba
  3. cba1
  4. 1cba
Check your answer

c1ba. StringBuffer has the same API as StringBuilder: append gives "ab1c", then reverse gives "c1ba".

You build a message inside one method and return it. Which class should you use?

  1. StringBuilder
  2. StringBuffer
  3. String with += in a loop
  4. char[] with manual resizing
Check your answer

StringBuilder. A local builder is only used by one thread, so StringBuffer's locking is wasted work. StringBuilder is the modern default.

Next: turning 3.14159 into 3.14 and lining up columns like a receipt โ€” formatting text.