Java StringBuffer Class
Last modified: April 13, 2025
The java.lang.StringBuffer class is a thread-safe, mutable sequence
of characters. Unlike String objects, StringBuffer can be modified after
creation. It provides various methods for string manipulation operations.
StringBuffer is similar to StringBuilder but with one key difference: all its methods are synchronized, making it thread-safe. This makes StringBuffer a good choice when working with strings in multi-threaded environments.
StringBuffer Class Methods
The StringBuffer class provides many methods for string manipulation. These include methods for appending, inserting, deleting, and reversing content. The class also provides capacity management methods.
public final class StringBuffer {
public StringBuffer() {...}
public StringBuffer(int capacity) {...}
public StringBuffer(String str) {...}
public synchronized StringBuffer append(...) {...}
public synchronized StringBuffer insert(...) {...}
public synchronized StringBuffer delete(...) {...}
public synchronized StringBuffer reverse() {...}
public synchronized int length() {...}
public synchronized int capacity() {...}
public synchronized void ensureCapacity(int minimum) {...}
public synchronized char charAt(int index) {...}
public synchronized void setCharAt(int index, char ch) {...}
public synchronized String substring(...) {...}
public synchronized String toString() {...}
}
The code above shows the main methods provided by the StringBuffer class. These methods allow for flexible string manipulation while maintaining thread safety.
Creating StringBuffer Objects
StringBuffer objects can be created in several ways: with no initial content, with an initial string, or with a specified initial capacity. The capacity determines how much memory is initially allocated.
package com.zetcode;
public class Main {
public static void main(String[] args) {
// Empty StringBuffer with default capacity (16)
StringBuffer sb1 = new StringBuffer();
System.out.println("sb1 capacity: " + sb1.capacity());
// StringBuffer with initial string
StringBuffer sb2 = new StringBuffer("Hello");
System.out.println("sb2 content: " + sb2);
System.out.println("sb2 capacity: " + sb2.capacity());
// StringBuffer with specified capacity
StringBuffer sb3 = new StringBuffer(50);
System.out.println("sb3 capacity: " + sb3.capacity());
// Adding content to empty buffer
sb1.append("Java StringBuffer");
System.out.println("sb1 content: " + sb1);
}
}
This example demonstrates different ways to create StringBuffer objects. The default constructor creates an empty buffer with capacity 16. The String constructor creates a buffer with the string content and appropriate capacity.
append Method
The append method adds content to the end of the StringBuffer. It
is overloaded to accept various data types including primitives, objects, and
character arrays. The method returns the same StringBuffer for method chaining.
package com.zetcode;
public class Main {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer();
// Appending different types
sb.append("String: ");
sb.append(100); // int
sb.append(' '); // char
sb.append(true); // boolean
sb.append(3.14); // double
sb.append(new char[]{'a', 'b', 'c'}); // char array
System.out.println("After append: " + sb);
// Method chaining
sb.append(" more ").append("text");
System.out.println("After chaining: " + sb);
// Capacity grows automatically
System.out.println("Final capacity: " + sb.capacity());
}
}
This example shows how the append method can handle different data
types. The StringBuffer automatically grows its capacity when needed. Method
chaining allows for concise code by returning the StringBuffer reference.
insert Method
The insert method adds content at a specified position in the
StringBuffer. Like append, it supports various data types. The position must be
within the current bounds of the buffer.
package com.zetcode;
public class Main {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("Java is great");
// Insert at position 4
sb.insert(4, " programming");
System.out.println("After first insert: " + sb);
// Insert different types
sb.insert(0, 2023); // int
sb.insert(4, ' '); // char
sb.insert(5, true); // boolean
System.out.println("After multiple inserts: " + sb);
// Insert at the end (same as append)
sb.insert(sb.length(), " language");
System.out.println("Final result: " + sb);
// Invalid position throws exception
try {
sb.insert(100, "error");
} catch (StringIndexOutOfBoundsException e) {
System.out.println("Caught exception: " + e.getMessage());
}
}
}
This example demonstrates the insert method with different data
types. We show valid insert positions and what happens when attempting to insert
at an invalid position. Inserting at length() is equivalent to append.
delete and deleteCharAt Methods
The delete method removes a sequence of characters between specified
indices. The deleteCharAt method removes a single character at a
specified position. Both methods adjust the buffer contents accordingly.
package com.zetcode;
public class Main {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("Java StringBuffer Example");
// Delete range (start inclusive, end exclusive)
sb.delete(5, 17);
System.out.println("After delete: " + sb);
// Delete single character
sb.deleteCharAt(5);
System.out.println("After deleteCharAt: " + sb);
// Delete from start
sb.delete(0, 4);
System.out.println("After deleting first word: " + sb);
// Delete to end
sb.delete(5, sb.length());
System.out.println("After deleting suffix: " + sb);
// Invalid indices throw exception
try {
sb.delete(10, 5);
} catch (StringIndexOutOfBoundsException e) {
System.out.println("Caught exception: " + e.getMessage());
}
}
}
This example shows various deletion operations. The delete method removes characters between two indices (start inclusive, end exclusive). We demonstrate deleting ranges, single characters, and handling invalid indices.
reverse Method
The reverse method reverses the sequence of characters in the
StringBuffer. This operation is performed in place, modifying the original
buffer. The method returns the StringBuffer reference for method chaining.
package com.zetcode;
public class Main {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("Hello World");
System.out.println("Original: " + sb);
// Reverse the content
sb.reverse();
System.out.println("Reversed: " + sb);
// Reverse back to original
sb.reverse();
System.out.println("Reversed again: " + sb);
// Palindrome check
StringBuffer palindrome = new StringBuffer("madam");
System.out.println(palindrome + " is palindrome: " +
palindrome.toString().equals(palindrome.reverse().toString()));
// Method chaining
System.out.println(new StringBuffer("abc")
.append("def")
.reverse()
.insert(3, "---"));
}
}
This example demonstrates the reverse method. We show simple
reversal, palindrome checking, and method chaining combining reverse with other
StringBuffer operations. The reversal affects the original buffer directly.
Capacity Management
StringBuffer manages memory using a capacity system. The capacity is the amount
of allocated memory, while length is the actual content size. Methods like
ensureCapacity and setLength help manage this.
package com.zetcode;
public class Main {
public static void main(String[] args) {
// Default capacity is 16
StringBuffer sb = new StringBuffer();
System.out.println("Initial capacity: " + sb.capacity());
System.out.println("Initial length: " + sb.length());
// Adding content grows capacity as needed
sb.append("This is a long string that exceeds default capacity");
System.out.println("After append - capacity: " + sb.capacity());
System.out.println("After append - length: " + sb.length());
// Ensure minimum capacity
sb.ensureCapacity(100);
System.out.println("After ensureCapacity(100): " + sb.capacity());
// Set explicit length
sb.setLength(10);
System.out.println("After setLength(10): " + sb);
System.out.println("New length: " + sb.length());
// Trim to size
sb.trimToSize();
System.out.println("After trimToSize - capacity: " + sb.capacity());
}
}
This example demonstrates StringBuffer capacity management. The buffer
automatically grows when needed, but we can also pre-allocate space with
ensureCapacity. setLength can truncate or expand the
content, while trimToSize reduces capacity to match length.
Thread Safety Demonstration
StringBuffer's thread safety makes it suitable for multi-threaded environments. Multiple threads can safely call StringBuffer methods without external synchronization. This example demonstrates this behavior.
package com.zetcode;
public class Main {
public static void main(String[] args) throws InterruptedException {
final StringBuffer sharedBuffer = new StringBuffer();
// Create multiple threads that append to the same buffer
Thread[] threads = new Thread[5];
for (int i = 0; i < threads.length; i++) {
final int threadId = i;
threads[i] = new Thread(() -> {
for (int j = 0; j < 10; j++) {
sharedBuffer.append("Thread " + threadId + ": " + j + "\n");
try {
Thread.sleep(10); // Simulate work
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
}
// Start all threads
for (Thread t : threads) {
t.start();
}
// Wait for all threads to complete
for (Thread t : threads) {
t.join();
}
// Verify all additions were made safely
System.out.println("Final buffer content:");
System.out.println(sharedBuffer);
System.out.println("Total length: " + sharedBuffer.length());
}
}
This example demonstrates StringBuffer's thread safety. Multiple threads concurrently append to the same StringBuffer without data corruption. The synchronized methods ensure that all operations complete atomically. The final length confirms all additions were preserved.
Source
Java StringBuffer Class Documentation
In this article, we've covered all major aspects of the Java StringBuffer class with practical examples. StringBuffer provides thread-safe, mutable string operations essential for complex string manipulation in multi-threaded contexts.
Author
List all Java tutorials.