Java StringBuffer
Table of Contents + −
In the last lesson you learned about Java StringBuilder. Now meet its close cousin, the StringBuffer. Same job, same methods, with one extra thing: thread safety.
🤔 What problem does StringBuffer solve?
A thread is just a separate line of work running alongside your main code. Picture two threads writing to the same buffer at once:
- They collide. One reads while the other writes half a step later.
- The text comes out wrong or corrupted.
- The bug is hard to catch. It only shows up when the timing lines up badly.
A plain StringBuilder assumes one thread, so it does no locking. A StringBuffer is built for the shared case:
- Every method is synchronized, so only one thread runs it at a time.
- The others wait their turn.
- So two threads never touch the buffer at once, and the text stays correct.
What synchronized means here
Synchronized is Java’s way of saying “one at a time”. When a method is synchronized, a thread must take a lock before it runs the method, and it gives the lock back when it finishes. While one thread holds the lock, the others wait. That waiting is what keeps the shared buffer safe, and it is also what makes StringBuffer a little slower than StringBuilder.
🧱 Creating a StringBuffer
You make a StringBuffer with new, just like a StringBuilder. Start it empty or hand it some text.
StringBuffer sb = new StringBuffer(); // starts emptyStringBuffer greeting = new StringBuffer("Hello"); // starts with text insidesbis an empty, changeable buffer;greetingalready holds “Hello”.- This looks identical to StringBuilder on purpose. Same shape, same way to read and write.
- The only difference is under the hood, in how they handle many threads.
➕ Building text with append
append() is the method you will use most. This builds “Hello World” by appending three pieces to one buffer.
StringBuffer sb = new StringBuffer();sb.append("Hello");sb.append(" ");sb.append("World");
System.out.println(sb.toString()); // turn it into a real String to print- Each
appendadds to the end of the same buffer, so no new objects are made. toString()turns the buffer into a normal String for printing.appendtakes anything: Strings, numbers likeappend(42), achar, aboolean, even another object. Java turns each into text first.- Each
appendreturns the same buffer, so you can chain:sb.append(a).append(b).
Output
Hello World🛠️ The core methods
Same toolbox as StringBuilder. All of these change the buffer directly, no new object. This shows insert, append, and reverse on one buffer, then replace on another.
StringBuffer sb = new StringBuffer("Hello");
sb.insert(0, ">> "); // add text at a position, push the rest rightsb.append(" World"); // add to the endsb.reverse(); // flip the whole thingSystem.out.println(sb.toString());
StringBuffer name = new StringBuffer("Java");name.replace(0, 1, "L"); // replace index 0 up to (not including) 1 with "L"System.out.println(name.toString());insert(0, ">> ")puts text at index 0 and slides the rest right.append(" World")adds to the end.reverse()flips every character, so the line runs backwards.replace(0, 1, "L")swaps index 0 up to (not including) 1 with “L”. “Java” becomes “Lava”.
Output
dlroW olleH >>LavaNow the removal methods. This deletes a range of characters, then a single character.
StringBuffer code = new StringBuffer("ABCDEF");
code.delete(1, 3); // remove index 1 up to (not including) 3 -> removes "BC"System.out.println(code.toString()); // ADEF
code.deleteCharAt(0); // remove the single character at index 0System.out.println(code.toString()); // DEFdelete(start, end)removes a whole range;deleteCharAt(index)removes one character.- The “up to but not including the end” rule applies to
delete, just likereplace.
Output
ADEFDEFTwo read methods come up a lot too. length() counts the characters inside; capacity() is the room the buffer has set aside.
StringBuffer text = new StringBuffer("Hello World");
System.out.println(text.length()); // 11 characters right nowSystem.out.println(text.capacity()); // room reserved, usually a bit morelength()is the count of real characters;capacity()is the room behind them.- The buffer keeps extra space so it does not grow on every append.
- Append past that room and Java makes the buffer bigger and copies the contents over.
- You rarely need to think about it for everyday code.
Output
1127The methods you will reach for most, matching StringBuilder one for one.
| Method | What it does |
|---|---|
| append(x) | Adds x to the end |
| insert(i, x) | Inserts x at index i |
| delete(start, end) | Removes characters from start up to end |
| deleteCharAt(i) | Removes the one character at index i |
| replace(start, end, x) | Replaces that range with x |
| reverse() | Flips all the characters |
| length() | How many characters are inside |
| capacity() | How much room the buffer has set aside |
| toString() | Gives back a normal String |
🔁 A worked example
A few methods together in one small program. This builds a label, tidies it, and prints it.
public class BufferDemo { public static void main(String[] args) { StringBuffer sb = new StringBuffer("user");
sb.append("-2026"); // user-2026 sb.insert(0, "id:"); // id:user-2026 sb.replace(3, 7, "alex"); // id:alex-2026
System.out.println(sb.toString()); System.out.println("Length: " + sb.length()); }}- Start with “user”, append “-2026”, insert “id:” at the front.
- Then replace the four characters from index 3 up to 7 (“user”) with “alex”.
- Each step changes the same buffer, no new objects. At the end, print the text and its length.
Output
id:alex-2026Length: 12⚖️ StringBuilder vs StringBuffer
The two classes are nearly twins, same methods and same behavior on the text. The difference is thread safety and speed.
- StringBuffer is thread-safe. Synchronized methods let many threads share one buffer safely, but the safety check costs a little time, so it is slower.
- StringBuilder is not thread-safe. No locking, so it is faster, but two threads at once can corrupt the text.
- Use StringBuilder unless multiple threads share the same buffer. Most code builds text in one thread and never shares it, so StringBuilder is the right, faster pick.
The simple rule
One thread building the text? Use StringBuilder. Many threads sharing the same buffer at the same time? Use StringBuffer. When in doubt, it is almost always StringBuilder.
📊 String vs StringBuilder vs StringBuffer
The three main ways to hold text in Java, each for a different need.
| Type | Mutable? | Thread-safe? | Performance |
|---|---|---|---|
| String | No, fixed once made | Yes, because it never changes | Slow for repeated building |
| StringBuilder | Yes | No | Fastest for building text |
| StringBuffer | Yes | Yes, methods are synchronized | A bit slower than StringBuilder |
Quick way to remember it:
- String: safe but cannot change.
- StringBuilder: can change and is fast.
- StringBuffer: can change and is safe to share. You trade speed for safety down the list.
⚠️ Common Mistakes
A few StringBuffer slip-ups, with the wrong way and the right way.
Using StringBuffer everywhere when you do not need it. In single-thread code you pay for locking on every call and get nothing back, since there is no other thread to protect against.
// ❌ no other thread here, so the synchronized cost is wastedStringBuffer sb = new StringBuffer();for (int i = 0; i < 100000; i++) sb.append(i);
// ✅ single thread, so StringBuilder is the right, faster choiceStringBuilder sb2 = new StringBuilder();for (int i = 0; i < 100000; i++) sb2.append(i);Forgetting toString(). A StringBuffer is not a String. Call toString() to store it in a String variable or print it as clean text.
StringBuffer sb = new StringBuffer("Hi");
// ❌ this is a StringBuffer, not a StringString text = sb; // won't even compile
// ✅ convert it firstString text2 = sb.toString();Expecting equals to compare text. Like StringBuilder, StringBuffer.equals() checks if the two are the very same object, not the characters inside. Convert to a String first to compare text.
StringBuffer a = new StringBuffer("Hi");StringBuffer b = new StringBuffer("Hi");
// ❌ equals here compares the objects, not the text -> falseSystem.out.println(a.equals(b));
// ✅ compare the text by converting firstSystem.out.println(a.toString().equals(b.toString())); // trueThread-safe per method, not per task
StringBuffer makes each single method safe, like one append. It does not make a group of calls safe as one unit. If two threads each run several methods in a row and the order matters, you still need your own locking around the whole group. StringBuffer only guards one call at a time.
✅ Best Practices
Habits for using these buffers well.
- Prefer StringBuilder for single-thread code. This is almost every case. It is faster and does the same job.
- Reach for StringBuffer only when threads share one buffer. That is the one situation where its safety earns its cost.
- Chain your appends.
sb.append(a).append(b)reads cleanly and works on both classes. - Call
toString()at the end. Convert to a String once, after you finish building. - Keep String for fixed text. Names, labels, and simple joins do not need a buffer at all.
- Do not lock by reflex. Thread safety is not free. Only pay for it when you actually share data across threads.
🧩 What You’ve Learned
Let’s recap StringBuffer.
- ✅ A StringBuffer is a changeable, growable text buffer, just like StringBuilder.
- ✅ It has the same core methods:
append,insert,delete,deleteCharAt,replace,reverse,toString,length,capacity. - ✅ Its methods are synchronized, so many threads can share one buffer safely.
- ✅ That safety makes it a little slower than StringBuilder.
- ✅ Use StringBuilder for normal single-thread code; use StringBuffer only when threads truly share the buffer.
- ✅ Always call
toString()to turn a buffer into a real String.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
What makes StringBuffer different from StringBuilder?
Why: StringBuffer's methods are synchronized, making it safe for many threads but a bit slower.
- 2
Which should you use for normal single-thread text building?
Why: Use StringBuilder unless multiple threads share the buffer; it is faster and does the same job.
- 3
How do you turn a StringBuffer into a normal String?
Why: toString() converts the buffer's contents into a String.
- 4
Is a plain String thread-safe?
Why: A String is immutable, so it cannot be changed by any thread, which makes it safe to share.
🚀 What’s Next?
You now know all three text types and when to use each. We have leaned on the word immutable a lot. Next, why Java made Strings immutable, what that buys you, and the surprises it can cause.