StringBuffer in Java
StringBuffer is a changeable string, just like StringBuilder, with the same append, insert, delete, replace and reverse methods. It's actually the older of the two: it has existed since Java 1.0, while StringBuilder arrived in Java 5. The one difference is that every StringBuffer method is synchronized, which makes it safe to use from several threads at once, at a small cost in speed.
Same Methods, Same Results
public class Buffer {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("Order");
sb.append(" #").append(301).append(" for ").append("Advitha");
System.out.println(sb);
System.out.println(sb.length() + " characters");
sb.insert(0, "[NEW] ");
System.out.println(sb);
sb.reverse();
System.out.println(sb);
}
}Order #301 for Advitha
22 characters
[NEW] Order #301 for Advitha
ahtivdA rof 103# redrO ]WEN[Swap the word StringBuffer for StringBuilder and the program prints exactly the same. Both classes extend the same internal parent, AbstractStringBuilder, and share its code.
What "Synchronized" Means Here
When a method is synchronized, only one thread can run it on a given object at a time; other threads wait their turn. So if two threads append to the same StringBuffer simultaneously, the appends happen one after another and nothing is lost. Here's two threads each appending 100,000 characters to both kinds of builder:
public class Race {
public static void main(String[] args) throws Exception {
StringBuilder unsafe = new StringBuilder();
StringBuffer safe = new StringBuffer();
Runnable task = () -> {
for (int i = 0; i < 100_000; i++) {
unsafe.append('x');
safe.append('x');
}
};
Thread a = new Thread(task);
Thread b = new Thread(task);
a.start();
b.start();
a.join();
b.join();
System.out.println("StringBuffer length: " + safe.length());
System.out.println("StringBuilder length: " + unsafe.length());
}
}StringBuffer length: 200000
StringBuilder length: 197017The StringBuffer always ends with exactly 200,000 characters. The StringBuilder loses characters, a different number each run, because both threads sometimes write into the same slot at the same moment. (It can even crash with an ArrayIndexOutOfBoundsException.) Threads get their own lessons later in the course; for now, the point is what "thread-safe" protects you from.
Where You'll Still See It
| Place | Why |
|---|---|
| Code written before Java 5 | StringBuilder didn't exist yet |
Some older JDK APIs, such as Matcher.appendReplacement(StringBuffer, ...) | They were designed before Java 5 (newer overloads accept StringBuilder) |
| Interview questions | "What's the difference between String, StringBuffer and StringBuilder?" |
Common Mistakes
Choosing StringBuffer "to be safe" in single-threaded code. It just adds locking you don't need.
Thinking StringBuffer makes a whole sequence of calls atomic. Each call is synchronized on its own; "check, then append" across two calls can still interleave with another thread.
Interview Corner
What is StringBuffer?
StringBuffer is a mutable, thread-safe sequence of characters available since Java 1.0. Its methods are synchronized, so multiple threads can modify the same instance without corrupting it. It has the same API as StringBuilder, which was added in Java 5 as a faster, unsynchronized alternative for single-threaded use.
Practice
- Easy: Rewrite the bill example from "StringBuilder in Java" with
StringBufferand confirm the output is identical. - Harder: Run
Race.javafive times and record theStringBuilderlength each time. Why does it change, and why does theStringBufferlength never change?
Key Takeaways
Was this tutorial helpful?