In Java, Strings are widely used for storing and manipulating textual data. However, if the content of the string is not fixed and needs to be changed frequently, using the String class is not recommended as it creates a new object every time a change is made, causing performance issues. In such cases, it is better to use the StringBuffer class.
StringBuffer
StringBuffer is a mutable sequence of characters that provides various methods to modify its content. The main advantage of StringBuffer over String is that all the required changes are performed on the existing object, avoiding the creation of new objects for each change. This improves performance and reduces memory consumption.
There are three constructors available for creating StringBuffer objects. The first constructor creates an empty StringBuffer object with a default capacity of 16. When the StringBuffer reaches its maximum capacity, a new StringBuffer object is created with a new capacity of (currentCapacity + 1) * 2. The second constructor creates an empty StringBuffer object with the specified initial capacity. The third constructor creates a StringBuffer object for a given String with a capacity of string.length() + 16.
StringBuffer provides several methods for manipulating its content. Some of the important methods are:
- length(): returns the length of the StringBuffer.
- capacity(): returns the total number of characters that the StringBuffer can accommodate.
- charAt(int index): returns the character at the specified index.
- setCharAt(int index, char ch): replaces the character at the specified index with the provided character.
- append(): appends the specified argument to the end of the StringBuffer. This method is overloaded for different argument types.
- insert(): inserts the specified argument at the specified index. This method is overloaded for different argument types.
- delete(int begin, int end): deletes characters from the begin index to end — 1 index.
- deleteCharAt(int index): deletes the character at the specified index.
- reverse(): reverses the content of the StringBuffer.
- setLength(int length): sets the length of the StringBuffer to the specified length.
- ensureCapacity(int capacity): increases the capacity of the StringBuffer based on our requirement.
- trimToSize(): deallocates extra allocated free memory.
StringBuilder
In addition to StringBuffer, there is another class called StringBuilder that provides similar functionality but is not synchronized. Every method present in StringBuffer is synchronized, allowing only one thread to operate on the StringBuffer object at a time, which may cause performance problems. To handle this problem, the StringBuilder concept was introduced in Java 1.5. StringBuilder is non-synchronized and multiple threads can operate on it at a time, making it faster than StringBuffer.
Examples
Example 1: Using StringBuffer to concatenate strings in a loop
String[] words = {"Hello", "world", "!"};
StringBuffer sb = new StringBuffer();
for (String word : words) {
sb.append(word);
}
String result = sb.toString(); // "Helloworld!"
In this example, we use a StringBuffer to concatenate the strings in the words
array inside a loop. Since we are performing multiple concatenations, it is more efficient to use a StringBuffer than to create new String objects with each concatenation.
Example 2: Using StringBuilder for single-threaded string operations
StringBuilder sb = new StringBuilder();
sb.append("The quick brown ");
sb.append("fox jumped over ");
sb.append("the lazy dog.");
String result = sb.toString(); // "The quick brown fox jumped over the lazy dog."
In this example, we use a StringBuilder to concatenate three strings together. Since there is no need for synchronization in this single-threaded example, we can use a StringBuilder instead of a StringBuffer for improved performance.
Example 3: Using StringBuffer for multi-threaded string operations
String[] words = {"The", "quick", "brown", "fox", "jumped", "over", "the", "lazy", "dog."};
StringBuffer sb = new StringBuffer();
Arrays.stream(words)
.parallel()
.forEach(word -> sb.append(word).append(" "));
String result = sb.toString(); // "The quick brown fox jumped over the lazy dog."
In this example, we use a StringBuffer to concatenate the strings in the words
array in a multi-threaded environment. Since StringBuffer is synchronized, it can safely be used by multiple threads. Note that if we were to use a StringBuilder instead of a StringBuffer in a multi-threaded environment, we could run into synchronization issues.
String Vs StringBuffer Vs StringBuilder
- If the content is fixed and won’t change frequently, we can use the String class.
- If the content is not fixed and keeps changing frequently, and we want thread safety, we can use the StringBuffer class.
- If the content is not fixed and keeps changing frequently, and we don’t want thread safety, we can use the StringBuilder class.