StringBuffer buffer = new StringBuffer("Hello");
buffer.append(" Java");
System.out.println(buffer);Java StringBuffer: Thread-Safe Mutable String Operations
Direct Answer & Core Concept
the String class, whose objects cannot be changed after creation, a StringBuffer object can be modified directly.
The important feature of StringBuffer is that its methods are synchronized, making it suitable for situations where the same mutable text object may be accessed by multiple threads.
For example, if a Java application needs to repeatedly append, insert, delete, or replace text while sharing the same buffer between threads, StringBuffer provides built-in synchronization.
Detailed Explanation & Mechanics
What Is StringBuffer in Java?
StringBuffer is a class in the java.lang package that represents a mutable sequence of characters.
Example:
Output:
Hello JavaThe existing StringBuffer object is modified when append() is called.
You can continue modifying it:
buffer.append(" Programming");
System.out.println(buffer);Output:
Hello Java ProgrammingWhy Use StringBuffer?
The main reason to use StringBuffer is when you need a mutable string-like object with synchronized methods.
Consider:
StringBuffer buffer = new StringBuffer();
buffer.append("Java");
buffer.append(" ");
buffer.append("Programming");
System.out.println(buffer);The same buffer is modified multiple times.
This is different from immutable String objects.
With String:
String text = "Java";
text = text + " Programming";A new string value is produced because String cannot be modified.
With StringBuffer:
StringBuffer buffer = new StringBuffer("Java");
buffer.append(" Programming");The existing buffer is changed.
StringBuffer vs String
The most important difference is mutability.
| Feature | String | StringBuffer |
|---|---|---|
| Mutable | No | Yes |
| Can modify existing object | No | Yes |
| Thread-safe | Yes, because immutable | Yes, through synchronization |
| Repeated modifications | Less suitable | Suitable |
| Synchronization overhead | Not applicable | Yes |
| Package | java.lang | java.lang |
Example:
String text = "Hello";
text = text + " World";The original String cannot be changed.
With StringBuffer:
StringBuffer buffer = new StringBuffer("Hello");
buffer.append(" World");The buffer itself is modified.
StringBuffer vs StringBuilder
This is one of the most important comparisons when learning Java strings.
Both classes are mutable.
The major difference is synchronization.
| Feature | StringBuilder | StringBuffer |
|---|---|---|
| Mutable | Yes | Yes |
| Synchronized methods | No | Yes |
| Thread-safe for its synchronized operations | No | Yes |
| Single-thread performance | Generally better | Generally lower due to synchronization overhead |
| Multi-thread shared mutable use | Requires external synchronization/design | Provides synchronized methods |
| Introduced | Java 5 | Java 1.0 |
Example:
StringBuilder builder = new StringBuilder();and:
StringBuffer buffer = new StringBuffer();Simple rule
Use StringBuilder when synchronization is not needed.
Use StringBuffer when you specifically need its synchronized mutable-string behavior.
Do not choose StringBuffer merely because it is "safer" without considering whether multiple threads actually share the same mutable object.
Creating a StringBuffer
There are several ways to create a StringBuffer.
1. Empty StringBuffer
StringBuffer buffer = new StringBuffer();The buffer initially contains no characters.
You can add text:
buffer.append("Hello");2. StringBuffer with Initial Text
StringBuffer buffer = new StringBuffer("Hello");The buffer starts with:
HelloYou can then modify it:
buffer.append(" Java");
System.out.println(buffer);Output:
Hello Java3. StringBuffer with Initial Capacity
You can specify an initial capacity:
StringBuffer buffer = new StringBuffer(100);This creates a buffer with an initial capacity of 100 characters.
Capacity and length are different concepts.
StringBuffer buffer = new StringBuffer(100);
System.out.println(buffer.length());
System.out.println(buffer.capacity());Output:
0100append() Method
append() adds content to the end of the buffer.
StringBuffer buffer = new StringBuffer("Hello");
buffer.append(" Java");
System.out.println(buffer);Output:
Hello JavaYou can append different types of data.
StringBuffer buffer = new StringBuffer();
buffer.append("Age: ");
buffer.append(35);
buffer.append(", Active: ");
buffer.append(true);
System.out.println(buffer);Output:
Age: 35, Active: trueAppending Characters
You can append a single character:
StringBuffer buffer = new StringBuffer("Java");
buffer.append('!');
System.out.println(buffer);Output:
Java!Appending Numbers
StringBuffer can append numeric values directly.
StringBuffer buffer = new StringBuffer();
buffer.append("Price: ");
buffer.append(999);
System.out.println(buffer);Output:
Price: 999Floating-point values also work:
buffer.append(" Discount: ");
buffer.append(10.5);insert() Method
The insert() method adds content at a specific position.
StringBuffer buffer = new StringBuffer("Hello World");
buffer.insert(6, "Java ");
System.out.println(buffer);Output:
Hello Java WorldThe syntax is:
insert(index, value)The inserted content begins at the specified index.
insert() with a Character
StringBuffer buffer = new StringBuffer("Jva");
buffer.insert(1, 'a');
System.out.println(buffer);Output:
Javadelete() Method
The delete() method removes characters between two indexes.
StringBuffer buffer = new StringBuffer("Hello Java");
buffer.delete(5, 10);
System.out.println(buffer);Output:
HelloRemember:
delete(start, end)The start index is included, while the end index is excluded.
deleteCharAt() Method
To remove one character, use deleteCharAt().
StringBuffer buffer = new StringBuffer("Java");
buffer.deleteCharAt(3);
System.out.println(buffer);Output:
JavThe character at index 3 was removed.
replace() Method
The replace() method replaces characters within a specified range.
StringBuffer buffer = new StringBuffer("Hello World");
buffer.replace(6, 11, "Java");
System.out.println(buffer);Output:
Hello JavaSyntax:
replace(start, end, newText)reverse() Method
The reverse() method reverses the characters in the buffer.
StringBuffer buffer = new StringBuffer("Java");
buffer.reverse();
System.out.println(buffer);Output:
avaJThis makes StringBuffer useful for simple reverse-string and palindrome exercises.
charAt() Method
charAt() returns the character at a specified index.
StringBuffer buffer = new StringBuffer("Java");
System.out.println(buffer.charAt(2));Output:
vIndexes start from zero:
J → 0a → 1v → 2a → 3setCharAt() Method
setCharAt() changes a character at a particular index.
StringBuffer buffer = new StringBuffer("Jova");
buffer.setCharAt(1, 'a');
System.out.println(buffer);Output:
JavaThis demonstrates the mutable nature of StringBuffer.
length() Method
The length() method returns the number of characters currently stored.
StringBuffer buffer = new StringBuffer("Java");
System.out.println(buffer.length());Output:
4After appending more text:
buffer.append(" Programming");
System.out.println(buffer.length());the length increases accordingly.
capacity() Method
capacity() returns the current amount of storage available before the buffer needs to expand.
StringBuffer buffer = new StringBuffer();
System.out.println(buffer.capacity());The default initial capacity is commonly 16.
You can specify your own:
StringBuffer buffer = new StringBuffer(100);
System.out.println(buffer.capacity());Output:
100Capacity vs Length
These concepts should not be confused.
StringBuffer buffer = new StringBuffer(50);
buffer.append("Java");
System.out.println("Length: " + buffer.length());
System.out.println("Capacity: " + buffer.capacity());Output:
Length: 4Capacity: 50Length
The number of characters currently stored.
Capacity
The amount of internal storage currently available before the buffer needs to grow.
ensureCapacity() Method
ensureCapacity() ensures that the buffer has at least the specified capacity.
StringBuffer buffer = new StringBuffer();
buffer.ensureCapacity(100);
System.out.println(buffer.capacity());This can be useful when you know that a large amount of text will be added.
Providing a reasonable initial capacity can reduce the number of internal resizing operations.
setLength() Method
setLength() changes the current length of the buffer.
For example:
StringBuffer buffer = new StringBuffer("Hello");
buffer.setLength(3);
System.out.println(buffer);Output:
HelThe extra characters were removed.
If the requested length is larger than the current length, additional null characters are introduced into the buffer.
toString() Method
toString() converts the StringBuffer contents into a normal immutable String.
StringBuffer buffer = new StringBuffer();
buffer.append("Hello");
buffer.append(" Java");
String result = buffer.toString();
System.out.println(result);Output:
Hello JavaThis is commonly used when the final result needs to be passed to a method or API that expects a String.
StringBuffer in a Loop
StringBuffer can be used to build text repeatedly.
StringBuffer buffer = new StringBuffer();
for (int i = 1;
i <= 10;
i++) {
buffer.append(i).append(" ");
}System.out.println(buffer);Output:
1 2 3 4 5 6 7 8 9 10This is more appropriate than repeatedly modifying immutable strings when there is substantial text construction.
Method Chaining
Many StringBuffer methods return the same buffer, so operations can be chained.
StringBuffer buffer = new StringBuffer();
buffer.append("Java") .append(" ") .append("Programming") .append(" ") .append("Language");
System.out.println(buffer);Output:
Java Programming LanguageMethod chaining can make repeated append operations concise.
StringBuffer and Thread Safety
Thread safety is the key feature that distinguishes StringBuffer from StringBuilder.
StringBuffer provides synchronized methods for many of its operations.
For example:
StringBuffer buffer = new StringBuffer();
buffer.append("Hello");
buffer.append(" World");The methods are synchronized, which helps coordinate access when multiple threads operate on the same buffer.
However, an important point is:
Synchronizing individual methods does not automatically make every multi-step sequence of operations atomic.
For example:
if (buffer.length() > 0) {
buffer.deleteCharAt(0);
}The check and deletion are two separate operations. If several threads share the same buffer, more careful synchronization may still be required around the complete operation depending on the application's requirements.
Simple Multithreading Example
Consider two threads writing to the same StringBuffer.
class MyTask extends Thread {
private StringBuffer buffer;
MyTask(StringBuffer buffer) {
this.buffer = buffer;
} @Override public void run() {
for (int i = 1;
i <= 5;
i++) {
buffer.append(i).append(" ");
}
}
}public class Main {
public static void main(String[] args) throws InterruptedException {
StringBuffer buffer = new StringBuffer();
Thread t1 = new MyTask(buffer);
Thread t2 = new MyTask(buffer);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(buffer);
}
}Both threads use the same StringBuffer.
The synchronized methods provide protection for the individual buffer operations.
The exact output order between threads is not guaranteed.
Important Thread-Safety Lesson
Thread safety does not mean that the output order is predictable.
For example, two threads may produce different valid orderings of their appended values.
The important distinction is:
Thread-safe ≠Predictable execution orderThread scheduling is controlled by the runtime and operating system.
StringBuffer and String Pool
StringBuffer is not itself a String Pool object.
For example:
String text = "Java";Here "Java" is a string literal.
But:
StringBuffer buffer = new StringBuffer("Java");creates a mutable StringBuffer object initialized using that text.
When you call:
String result = buffer.toString();you obtain a String.
Converting String to StringBuffer
You can initialize a StringBuffer using a String.
String text = "Hello Java";
StringBuffer buffer = new StringBuffer(text);
buffer.append(" Programming");
System.out.println(buffer);Output:
Hello Java ProgrammingConverting StringBuffer to String
Use toString().
StringBuffer buffer = new StringBuffer("Hello Java");
String text = buffer.toString();
System.out.println(text);This is the normal way to obtain an immutable String representation of the buffer.
Reverse a String Using StringBuffer
String text = "Programming";
StringBuffer buffer = new StringBuffer(text);
buffer.reverse();
System.out.println(buffer);Output:
gnimmargorPCheck Palindrome Using StringBuffer
A palindrome reads the same from left to right and right to left.
Examples:
madamlevelradarJava example:
public class PalindromeExample {
public static void main(String[] args) {
String text = "level";
StringBuffer buffer = new StringBuffer(text);
buffer.reverse();
if (text.equals(buffer.toString())) {
System.out.println("Palindrome");
} else {
System.out.println("Not a palindrome");
}
}
}Output:
PalindromeBuilding a Comma-Separated List
StringBuffer can be used to create formatted text.
StringBuffer buffer = new StringBuffer();
for (int i = 1;
i <= 5;
i++) {
buffer.append(i);
if (i < 5) {
buffer.append(", ");
}
}System.out.println(buffer);Output:
1, 2, 3, 4, 5This avoids having to remove a trailing comma afterward.
Creating a Sentence
StringBuffer sentence = new StringBuffer();
sentence.append("Java");
sentence.append(" is");
sentence.append(" a");
sentence.append(" popular");
sentence.append(" programming");
sentence.append(" language.");
System.out.println(sentence);Output:
Java is a popular programming language.Generating HTML with StringBuffer
A StringBuffer can also construct dynamic text such as simple HTML.
StringBuffer html = new StringBuffer();
html.append("<html>");
html.append("<body>");
html.append("<h1>Hello Java</h1>");
html.append("</body>");
html.append("</html>");
System.out.println(html);For larger applications, dedicated template engines are usually more maintainable than manually constructing large HTML documents.
StringBuffer and SQL
A buffer can technically be used to construct SQL text:
StringBuffer query = new StringBuffer();
query.append("SELECT name ");
query.append("FROM users ");
query.append("WHERE age > 18");
System.out.println(query);Output:
SELECT name FROM users WHERE age > 18However, never build SQL using untrusted user input through simple string concatenation.
For database applications, use parameterized queries or prepared statements to protect against SQL injection.
StringBuffer Performance
StringBuffer is designed for mutable character manipulation, but its synchronization introduces overhead compared with StringBuilder.
For a typical single-threaded operation:
StringBuilder builder = new StringBuilder();is generally preferred when no synchronization is required.
For a shared mutable buffer where synchronized methods are specifically useful:
StringBuffer buffer = new StringBuffer();may be appropriate.
The actual performance difference depends on the workload, Java implementation, runtime optimizations, and how the objects are used.
Should You Always Use StringBuffer?
No.
Choosing StringBuffer only because it is synchronized is not automatically the best design.
Ask:
Is the text modified repeatedly?
Is the mutable object shared between threads?
Do I need the synchronized behavior provided by
StringBuffer?Would a thread-local
StringBuilderor another design avoid shared mutable state?
If the code is single-threaded, StringBuilder is often the simpler choice.
String, StringBuilder, and StringBuffer
This is an important Java concept.
String↓Immutable↓Cannot modify existing objectStringBuilder↓Mutable↓Not synchronizedStringBuffer↓Mutable↓Synchronized methodsA practical comparison:
| Feature | String | StringBuilder | StringBuffer |
|---|---|---|---|
| Mutable | No | Yes | Yes |
| Thread-safe mutable operations | Not applicable | No | Yes, through synchronization |
| Best for repeated modifications | Not usually | Yes | Yes |
| Synchronization overhead | No | No | Yes |
| Typical single-thread choice | Yes for simple text | Yes for repeated building | Usually unnecessary |
| Shared mutable text | Immutable design | Requires care | Provides synchronization for its methods |
Common StringBuffer Mistakes
1. Confusing StringBuffer with String
This:
StringBuffer buffer = new StringBuffer("Java");does not create an immutable String.
The buffer remains mutable.
2. Assuming Thread Safety Means Everything Is Atomic
Individual synchronized operations do not automatically make a sequence of multiple operations atomic.
Be careful with compound operations.
3. Using StringBuffer in Every Program
If your application is single-threaded and simply needs efficient string construction, StringBuilder is often more appropriate.
4. Ignoring Index Boundaries
This can cause an exception:
StringBuffer buffer = new StringBuffer("Java");
buffer.charAt(10);Valid indexes are:
0, 1, 2, 35. Confusing Capacity and Length
buffer.length();means current number of characters.
buffer.capacity();means current internal capacity.
They are not the same thing.
Best Practices for StringBuffer
1. Use It When Synchronized Mutable Operations Are Needed
If multiple threads genuinely share a mutable character sequence, StringBuffer can be useful.
2. Prefer StringBuilder When Synchronization Is Unnecessary
Do not pay synchronization overhead without a reason.
3. Use toString() for the Final String
String result = buffer.toString();4. Provide an Initial Capacity When the Size Is Predictable
StringBuffer buffer = new StringBuffer(1000);This can reduce resizing when you know the approximate amount of content.
5. Be Careful with Compound Operations
Synchronization of individual methods does not make a multi-operation algorithm automatically atomic.
Important StringBuffer Methods
| Method | Purpose |
|---|---|
append() | Adds content to the end |
insert() | Inserts content at an index |
delete() | Deletes a range |
deleteCharAt() | Deletes one character |
replace() | Replaces a range |
reverse() | Reverses the characters |
charAt() | Reads a character |
setCharAt() | Changes a character |
length() | Returns current length |
capacity() | Returns current capacity |
ensureCapacity() | Ensures minimum capacity |
setLength() | Changes current length |
toString() | Converts to String |
Complete StringBuffer Example
public class StringBufferExample {
public static void main(String[] args) {
StringBuffer buffer = new StringBuffer();
// Append
buffer.append("Java");
// Add more text
buffer.append(" Programming");
System.out.println("After append: " + buffer);
// Insert
buffer.insert(5, "Language ");
System.out.println("After insert: " + buffer);
// Replace
buffer.replace(0, 4, "Advanced Java");
System.out.println("After replace: " + buffer);
// Delete
buffer.delete(0, 9);
System.out.println("After delete: " + buffer);
// Reverse
buffer.reverse();
System.out.println("After reverse: " + buffer);
// Convert to String
String result = buffer.toString();
System.out.println("Final String: " + result);
}
}This example demonstrates the most important StringBuffer operations in one program.
Real-World Use Cases
StringBuffer can be useful in situations such as:
Multi-threaded text construction
Multiple threads may need to work with the same mutable character sequence.
Dynamic message construction
Applications can build messages from multiple pieces.
Legacy Java applications
Older Java applications may already use StringBuffer.
Shared mutable text
When synchronized methods on a mutable character sequence fit the application design.
However, modern applications should still consider whether sharing mutable state is necessary at all.
Frequently Asked Questions
What is StringBuffer in Java?
StringBuffer is a mutable sequence of characters that provides synchronized methods for modifying its contents.
Is StringBuffer mutable?
Yes. You can modify its contents after creation.
Is StringBuffer thread-safe?
Its methods are synchronized, providing thread-safe behavior for individual operations on the same buffer.
Is StringBuffer faster than StringBuilder?
Usually not for single-threaded work. StringBuilder generally has less synchronization overhead.
What is the difference between StringBuffer and StringBuilder?
Both are mutable. StringBuffer provides synchronization, while StringBuilder does not.
What is the difference between String and StringBuffer?
String is immutable, while StringBuffer is mutable.
How do I reverse a StringBuffer?
Use:
buffer.reverse();How do I convert StringBuffer to String?
Use:
String result = buffer.toString();What does append() do?
It adds content to the end of the existing buffer.
What does insert() do?
It inserts content at a specified index.
What does capacity() mean?
It represents the current amount of internal storage available before the buffer needs to grow.
Is StringBuffer synchronized?
Yes. Its methods are synchronized.
Should I use StringBuffer instead of StringBuilder?
Only when the synchronization provided by StringBuffer is actually useful for your application. For ordinary single-threaded string construction, StringBuilder is generally preferred.
Practice Questions
Beginner
What is
StringBufferin Java?Is
StringBuffermutable?What does
append()do?What does
reverse()do?What does
length()return?What does
capacity()return?
Intermediate
Write a Java program to reverse a string using
StringBuffer.Write a program to check whether a word is a palindrome.
Use
append()to create a sentence.Use
insert()to add text to an existing sentence.Use
delete()to remove a portion of a string.Use
setCharAt()to change a character.
Advanced
Why is
StringBuffersynchronized?What is the difference between
StringBuilderandStringBuffer?Why can
StringBuilderbe faster thanStringBuffer?Does synchronization of individual methods make a multi-step operation atomic?
Explain the difference between capacity and length.
When would you choose
StringBufferinstead ofStringBuilder?
Quick Revision
Remember these important points:
StringBufferis mutable.It belongs to the
java.langpackage.Its methods are synchronized.
It is designed for mutable character sequences.
append()adds content.insert()inserts content.delete()removes a range.deleteCharAt()removes one character.replace()replaces a range.reverse()reverses the buffer.charAt()reads a character.setCharAt()changes a character.length()returns the current number of characters.capacity()returns the current internal capacity.toString()converts the buffer into aString.StringBuffergenerally has more synchronization overhead thanStringBuilder.StringBuilderis usually preferred when thread synchronization is not required.Synchronizing individual methods does not automatically make a sequence of multiple operations atomic.
Graphic and Design Ideas
Graphic 1: String vs StringBuilder vs StringBuffer
Create a three-column comparison:
┌─────────────┬────────────────┬─────────────────┐
│ String │ StringBuilder │ StringBuffer │
├─────────────┼────────────────┼─────────────────┤
│ Immutable │ Mutable │ Mutable │
│ No sync │ No sync │ Synchronized │
│ Simple text │ Fast building │ Shared mutable │
└─────────────┴────────────────┴─────────────────┘Graphic 2: StringBuffer Workflow
Create StringBuffer↓append()↓insert()↓replace()↓delete()↓reverse()↓toString()↓Final StringGraphic 3: Thread-Safety Concept
Show two threads accessing a shared buffer:
Thread 1 ──────┐
↓
StringBuffer
↑
Thread 2 ──────┘
synchronized
methodsThe graphic should explain that synchronization protects individual operations; it should not imply that thread execution order is guaranteed.
Graphic 4: Mutable String Concept
String"Java"↓modificationNew String valueStringBuffer"Java"↓append()"Java Programming"↓append()"Java Programming Language"The visual should emphasize that StringBuffer is mutable.
Runnable Code Example: Java StringBuffer
Java 17+public class StringBufferDemo {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("Concurrent");
sb.append(" Safe Buffer");
System.out.println("Buffer content: " + sb.toString());
System.out.println("Capacity: " + sb.capacity());
}
}