StringBuffer in Java
-
Last Updated: January 16, 2025
-
By: javahandson
-
Series
Explore StringBuffer in Java with this detailed guide. Learn its key features, constructors, and methods, and understand memory management to handle thread-safe string manipulation efficiently.
StringBuffer is a class in Java that represents a mutable sequence of characters. Unlike immutable String, StringBuffer allows modifications such as appending, inserting, deleting, or replacing characters without creating new objects. StringBuffer is part of the java.lang package.
StringBuffer objects are mutable meaning their content can be modified after creation. Unlike String, when we use StringBuffer modifications such as appending, inserting, or deleting characters do not create new objects.
package com.java.handson.strings;
public class StringBufferDemo {
public static void main(String[] args) {
String str = "Java";
System.out.println("Memory location of str: " + Integer.toHexString(System.identityHashCode(str)));
str += " HandsOn"; // Creates a new String object
System.out.println("Memory location of str: " + Integer.toHexString(System.identityHashCode(str)));
System.out.println(str);
StringBuffer stringBuffer = new StringBuffer("Java");
System.out.println("Memory location of stringBuffer: " + Integer.toHexString(System.identityHashCode(str)));
stringBuffer.append(" HandsOn"); // Modifies the same StringBuffer object
System.out.println("Memory location of stringBuffer: " + Integer.toHexString(System.identityHashCode(str)));
System.out.println(stringBuffer);
}
}
Output:
Memory location of str: 16d3586
Memory location of str: 154617c
Java HandsOn
Memory location of stringBuffer: 154617c
Memory location of stringBuffer: 154617c
Java HandsOn
In the above program, we can see str points to different locations when a new string is appended whereas in the case of StringBuffer, the same object gets modified and prints the same memory location.
All the methods of StringBuffer are synchronized making it thread-safe. This means it can be safely used in multithreaded environments as only one thread can access or modify a StringBuffer object at a time.
package com.java.handson.strings;
public class StringBufferDemo {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("Java");
// Create multiple threads that append to the same StringBuffer
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 3; i++) {
System.out.println("Inside thread-1");
sb.append(" HandsOn");
System.out.println("Thread 1 appended HandsOn : " + sb);
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 3; i++) {
System.out.println("Inside thread-2");
sb.append(" handsOn");
System.out.println("Thread 2 appended handsOn : " + sb);
}
});
// Start the threads
thread1.start();
thread2.start();
// Wait for both threads to complete
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// Final content of the StringBuffer
System.out.println("Final StringBuffer content: " + sb);
}
}
Output:
Inside thread-1
Inside thread-2
Thread 1 appended HandsOn : Java HandsOn
Inside thread-1
Thread 1 appended HandsOn : Java HandsOn handsOn HandsOn
Inside thread-1
Thread 1 appended HandsOn : Java HandsOn handsOn HandsOn HandsOn
Thread 2 appended handsOn : Java HandsOn handsOn
Inside thread-2
Thread 2 appended handsOn : Java HandsOn handsOn HandsOn HandsOn handsOn
Inside thread-2
Thread 2 appended handsOn : Java HandsOn handsOn HandsOn HandsOn handsOn handsOn
Final StringBuffer content: Java HandsOn handsOn HandsOn HandsOn handsOn handsOn
In the above program, the StringBuffer sb object is shared between multiple threads (thread1 and thread2). Since the methods in StringBuffer are synchronized, only one thread can modify the StringBuffer at a time, ensuring no corruption of data. The exact order of output may vary, but the data remains consistent because of thread safety.
StringBuffer manages its capacity dynamically. When the current capacity is exceeded, it automatically increases its size (usually doubles). This makes it efficient for building or modifying large strings.
package com.java.handson.strings;
public class StringBufferDemo {
public static void main(String[] args) {
// Create a StringBuffer with an initial capacity of 10
StringBuffer sb = new StringBuffer(10);
// Print the initial capacity
System.out.println("Initial capacity: " + sb.capacity()); // Output: 10
// Append a string that fits within the current capacity
sb.append("Java");
System.out.println("Content: " + sb);
System.out.println("Capacity after adding 'Java': " + sb.capacity()); // Capacity remains 10
// Append more characters to exceed the current capacity
sb.append(" HandsOn! Learn Java in depth");
System.out.println("Content: " + sb);
System.out.println("Capacity after exceeding initial capacity: " + sb.capacity()); // Capacity increases dynamically
// Further appending more characters
sb.append(" Dynamic resizing ensures efficiency.");
System.out.println("Content: " + sb);
System.out.println("Final capacity: " + sb.capacity());
}
}
Output:
Initial capacity: 10
Content: Java
Capacity after adding 'Java': 10
Content: Java HandsOn! Learn Java in depth
Capacity after exceeding initial capacity: 33
Content: Java HandsOn! Learn Java in depth Dynamic resizing ensures efficiency.
Final capacity: 70
In the above program, when appending strings if the total content exceeds the current capacity, then the buffer grows dynamically.
The new capacity is calculated as: newCapacity = (currentCapacity * 2) + 4 (this is the formula used internally).
The formula (currentCapacity * 2) + 4 is a newer resizing strategy introduced in some versions of JDK to provide a better balance between memory usage and performance. The additional growth of +4 ensures that the buffer doesn’t resize too frequently in cases where only a small number of characters are appended beyond the current capacity.
While StringBuffer is slower than StringBuilder due to synchronization, it is still significantly faster than String for frequent modifications because it avoids creating new objects. Please find the link to the StringBuilder article here.
StringBuffer provides methods like toString() to convert the buffer back to a String for compatibility with APIs that require a String.
package com.java.handson.strings;
public class StringBufferDemo {
public static void main(String[] args) {
// Create a StringBuffer
StringBuffer sb = new StringBuffer("Java");
// Append more content
sb.append(" HandsOn");
// Convert StringBuffer to String
String str = sb.toString();
// Print the StringBuffer content
System.out.println("StringBuffer content: " + sb);
// Print the converted String
System.out.println("Converted String content: " + str);
// Use the String in a String-specific operation
System.out.println("String in uppercase: " + str.toUpperCase());
}
}
Output:
StringBuffer content: Java HandsOn
Converted String content: Java HandsOn
String in uppercase: JAVA HANDSON
1. StringBuffer() – Creates an empty StringBuffer with an initial capacity of 16 characters.
StringBuffer sb = new StringBuffer();
System.out.println("Capacity: " + sb.capacity()); // Output: 16
2. StringBuffer(int capacity) – Creates a StringBuffer with the specified initial capacity.
StringBuffer sb = new StringBuffer(50);
System.out.println("Capacity: " + sb.capacity()); // Output: 50
3. StringBuffer(String str) – Creates a StringBuffer initialized with the content of the given String. The initial capacity will be the length of the string + 16.
StringBuffer sb = new StringBuffer("Java");
System.out.println("Content: " + sb); // Output: Java
System.out.println("Capacity: " + sb.capacity()); // Output: 20 (4 + 16)
4. StringBuffer(CharSequence cs) – Creates a StringBuffer initialized with the content of the given CharSequence.
CharSequence cs = "Java";
StringBuffer sb = new StringBuffer(cs);
System.out.println("Content: " + sb); // Output: Java
Here are the frequently used methods:
1. append(String str) – Appends the specified string to the end of the current StringBuffer.
StringBuffer sb = new StringBuffer("Java");
sb.append(" HandsOn");
System.out.println(sb); // Output: Java HandsOn
2. insert(int index, String str) – Inserts the specified string at the given index.
StringBuffer sb = new StringBuffer("Ja va");
sb.insert(2, " HandsOn");
System.out.println(sb); // Output: Ja HandsOn va
3. replace(int start, int end, String str) – Replaces the characters in a specified range with the given string.
StringBuffer sb = new StringBuffer("Java Hello");
sb.replace(5, 10, "HandsOn");
System.out.println(sb); // Output: Java HandsOn
4. delete(int start, int end) – Deletes the characters from the specified start index to the end index. The end index is excluded.
StringBuffer sb = new StringBuffer("Java HandsOn");
sb.delete(5, 10);
System.out.println(sb); // Output: Java On
5. deleteCharAt(int index) – Deletes the character at the specified index.
StringBuffer sb = new StringBuffer("Java H");
sb.deleteCharAt(5);
System.out.println(sb); // Output: Java
6. reverse() – Reverses the sequence of characters in the StringBuffer.
StringBuffer sb = new StringBuffer("Java HandsOn");
sb.reverse();
System.out.println(sb); // Output: nOsdnaH avaJ
7. capacity() – Returns the current capacity of the buffer.
StringBuffer sb = new StringBuffer();
System.out.println("Capacity: " + sb.capacity()); // Output: 16
8. length() – Returns the number of characters currently present in the StringBuffer.
StringBuffer sb = new StringBuffer("Java HandsOn");
System.out.println("Length: " + sb.length()); // Output: 12
9. setLength(int newLength) – Sets the length of the StringBuffer. If the new length is less than the current length it truncates the buffer but if it’s more then it pads with null (\u0000).
StringBuffer sb = new StringBuffer("Java HandsOn");
sb.setLength(4);
System.out.println(sb); // Output: Java
sb.setLength(6);
System.out.println(sb); // Output: Java\u0000\u0000
10. ensureCapacity(int minimumCapacity) – Ensures that the StringBuffer has at least the specified capacity.
StringBuffer sb = new StringBuffer();
sb.ensureCapacity(50);
System.out.println("Capacity: " + sb.capacity()); // Output: 50
11. charAt(int index) – Returns the character at the specified index.
StringBuffer sb = new StringBuffer("Java");
System.out.println(sb.charAt(2)); // Output: v
12. substring(int start, int end) – Returns a new String containing characters from the specified range.
StringBuffer sb = new StringBuffer("Java HandsOn");
String str = sb.substring(5, 12);
System.out.println(str); // Output: HandsOn
StringBuffer in Java handles memory dynamically and efficiently through the use of an internal character array. It manages memory by automatically resizing the array when the buffer’s capacity is exceeded.
1. Internally, StringBuffer uses a char array to store the sequence of characters. Initially, the array has a certain default capacity (usually 16 characters for an empty StringBuffer). The array is capable of resizing when more space is required to store characters.
Length: The length represents the number of characters actually in the StringBuffer.
Capacity: The capacity is the total amount of space allocated in memory for the StringBuffer, which is often larger than the length. It ensures that there is extra space for future modifications.
2. When the length exceeds the current capacity, the StringBuffer automatically doubles the capacity (and adds 4 in some cases) to accommodate new characters. This resizing happens internally without any intervention from the programmer. The resizing ensures that the StringBuffer is efficiently utilized and can grow without frequently allocating new arrays.
3. The idea behind growing the array size exponentially (doubling the capacity) is to reduce the number of reallocations. This results in fewer expensive memory copying operations making it more efficient as the buffer grows. The buffer grows to the next power of two and this ensures that the memory is used efficiently without over-allocating.
4. As with any other Java object, the char array inside the StringBuffer will be garbage-collected when the StringBuffer object is no longer referenced. However, the underlying array is not shrinkable. Once memory is allocated it remains allocated until the object is destroyed.
In this article, we explored the core aspects of StringBuffer, a powerful class in Java used for handling mutable strings efficiently. We covered its key features such as dynamic resizing, thread safety, and compatibility with String objects. We also delved into the constructors and the wide range of methods available to manipulate strings, as well as how memory management works internally to ensure optimal performance.
While StringBuffer is thread-safe and useful in multi-threaded environments, developers should consider using StringBuilder in single-threaded applications for better performance. Understanding when and how to use StringBuffer in your Java projects can help you write more efficient, thread-safe code, especially in legacy systems or multi-threaded applications where concurrent modifications of strings are required.
By mastering StringBuffer, Java developers can ensure smoother string manipulations in a variety of scenarios.
So this is all about the StringBuffer in Java. If you have any questions on this topic, please raise them in the comments section. If you liked this article then please share this post with your friends and colleagues.