← Back to Home

StringBuffer

The StringBuffer class in Java is a foundational component for handling mutable string operations in a thread-safe manner. While many developers begin their journey with the java-string-class">String class, they soon encounter its limitations—particularly its immutability. This is where StringBuffer becomes relevant. It is specifically designed for scenarios where strings need to be modified frequently and where multiple threads may interact with the same object concurrently.

StringBuffer in Java

Understanding StringBuffer is not just about learning another class; it is about understanding how Java balances performance, safety, and memory efficiency. In real-world applications—especially in legacy systems and multi-threaded environments—StringBuffer plays a crucial role. It is also a frequently discussed topic in interviews, particularly when comparing it with String and StringBuilder.

What Is StringBuffer?

StringBuffer is a mutable sequence of characters provided by the java.lang package. Unlike String, which creates a new object every time it is modified, StringBuffer allows direct modification of its internal character array. This means operations like appending, inserting, or deleting characters do not result in new object creation.

Another defining characteristic of StringBuffer is that it is thread-safe. All of its major methods are synchronized, which ensures that only one thread can access a method at a time. This prevents data inconsistency when multiple threads attempt to modify the same string simultaneously.

A simple example illustrates its usage:

StringBuffer sb = new StringBuffer("Java");
sb.append(" World");

In this case, the original object is modified rather than creating a new one, making it more efficient than repeated string concatenation using String.

Why StringBuffer Exists

To understand why StringBuffer exists, it is important to consider the limitations of the String class. Strings in Java are immutable, meaning once a string is created, it cannot be changed. Any modification results in the creation of a new object. While this design improves security and thread safety, it becomes inefficient when frequent modifications are required.

For example, concatenating strings inside a loop using String can lead to excessive object creation, which negatively impacts performance and memory usage.

To address this, Java introduced mutable alternatives:

  • StringBuilder for high-performance, single-threaded scenarios
  • StringBuffer for thread-safe, multi-threaded scenarios

StringBuffer bridges the gap between immutability and concurrency by allowing modifications while ensuring thread safety through synchronization.

Key Characteristics of StringBuffer

The behavior of StringBuffer can be summarized through its core characteristics. It is mutable, meaning its content can be changed without creating new objects. It is synchronized, ensuring thread safety in concurrent environments. It allows efficient string manipulation, making it suitable for dynamic string operations.

However, this thread safety comes at a cost. Because methods are synchronized, there is a performance overhead compared to non-synchronized alternatives like StringBuilder. This trade-off is central to deciding when to use StringBuffer.

How StringBuffer Works Internally

Internally, StringBuffer maintains a resizable array of characters. When a new StringBuffer object is created, it allocates a certain capacity. As characters are added, the buffer grows dynamically.

When you perform an operation like append(), the new characters are added to the existing array. If the capacity is exceeded, a new larger array is created, and the existing content is copied into it.

For example:

StringBuffer sb = new StringBuffer("Java");
sb.append(" Programming");

Here, the same object is modified, and no new StringBuffer object is created. This is fundamentally different from how String works.

Constructors of StringBuffer

StringBuffer provides multiple constructors to accommodate different use cases. The default constructor initializes the buffer with a capacity of 16 characters. Another constructor allows initializing the buffer with a specific string, while a third allows specifying a custom capacity.

For example:

StringBuffer sb1 = new StringBuffer();
StringBuffer sb2 = new StringBuffer("Java");
StringBuffer sb3 = new StringBuffer(50);

These constructors give developers control over initial capacity, which can help optimize performance by reducing the need for frequent resizing.

Capacity Concept (Critical for Performance)

One of the most important aspects of StringBuffer is its capacity management. Capacity refers to the amount of storage available before the buffer needs to be resized.

By default, the capacity is 16. When initialized with a string, the capacity becomes 16 plus the length of the string.

When the capacity is exceeded, the buffer grows using the formula:

newCapacity = (oldCapacity * 2) + 2

This resizing strategy ensures that the buffer grows efficiently without frequent reallocations. However, in performance-critical applications, it is often recommended to initialize the buffer with an appropriate capacity to minimize resizing overhead.

Commonly Used Methods

StringBuffer provides a rich set of methods for string manipulation. The append() method is used to add content to the end of the buffer. The insert() method allows inserting characters at a specific position. The replace() method replaces a portion of the string, while delete() removes characters.

The reverse() method is particularly useful for reversing the sequence of characters. Additionally, methods like length() and capacity() provide information about the current state of the buffer.

These methods enable a wide range of operations without creating new objects, making StringBuffer efficient for dynamic string handling.

Example Program

A simple example demonstrates multiple operations:

StringBuffer sb = new StringBuffer("Java");
sb.append(" Programming");
sb.insert(4, " Core");
sb.replace(0, 4, "Core");
sb.reverse();
System.out.println(sb);

In this example, all operations modify the same object. This highlights the key advantage of StringBuffer over String.

StringBuffer vs StringBuilder vs String

Understanding the differences between these three classes is essential. String is immutable and thread-safe by design, but inefficient for frequent modifications. StringBuilder is mutable and faster but not thread-safe. StringBuffer is mutable and thread-safe but slower due to synchronization.

In modern applications, StringBuilder is often preferred for single-threaded scenarios because of its superior performance. However, StringBuffer remains relevant when thread safety is required.

When to Use StringBuffer

StringBuffer should be used in scenarios where multiple threads need to modify the same string object. It is particularly useful in legacy systems, shared resources, and applications where thread safety is critical.

For example, in a multi-threaded logging system where multiple threads append messages to a shared buffer, StringBuffer ensures that the data remains consistent.

When NOT to Use StringBuffer

Despite its advantages, StringBuffer is not always the best choice. In single-threaded applications, the synchronization overhead is unnecessary and can degrade performance. In such cases, StringBuilder is a better alternative.

Similarly, for simple string operations or infrequent modifications, using String may be sufficient and more readable.

Choosing the right class depends on the specific requirements of the application, particularly the need for thread safety versus performance.

Common Beginner Mistakes

Many beginners misuse StringBuffer due to a lack of understanding of its purpose. One common mistake is using it in single-threaded applications where StringBuilder would be more efficient.

Another mistake is assuming that StringBuffer is always faster than String. While it avoids object creation, its synchronized methods introduce overhead that can make it slower in certain scenarios.

Confusing immutability with thread safety is another frequent issue. While String is thread-safe due to immutability, it does not support efficient modification.

Avoiding these mistakes requires a clear understanding of how each class works and when to use it.

Interview Perspective

In interviews, StringBuffer is often discussed in comparison with String and StringBuilder. A strong answer should highlight its mutability, thread safety, and performance trade-offs.

Candidates are typically expected to explain why StringBuffer is synchronized and how that affects performance. They should also be able to justify when to use it and when to avoid it.

Providing real-world scenarios, such as multi-threaded logging or shared resource handling, can strengthen the answer and demonstrate practical understanding.

Key Takeaway

StringBuffer is a mutable, thread-safe class designed for scenarios where strings need to be modified frequently in a multi-threaded environment. It eliminates the inefficiencies of immutable strings while ensuring data consistency through synchronization.

However, this thread safety comes at the cost of performance. For most modern applications, StringBuilder is preferred unless thread safety is explicitly required.

Ultimately, mastering StringBuffer is about understanding trade-offs—between immutability and mutability, between performance and safety, and between simplicity and scalability. Knowing when and how to use it is a key step toward writing efficient and robust Java applications.

1. Creating a StringBuffer Object

StringBuffer sb = new StringBuffer("Java");

Explanation

  • Creates a mutable sequence of characters.
  • Stored in heap memory.
  • Thread-safe (synchronized).

2. Default StringBuffer Constructor

StringBuffer sb = new StringBuffer();
System.out.println(sb.length());

Explanation

  • Creates empty buffer.
  • Initial length = 0.
  • Default capacity = 16.

3. StringBuffer with Initial Capacity

StringBuffer sb = new StringBuffer(50);
System.out.println(sb.capacity());

Explanation

  • Capacity reserved upfront.
  • Improves performance when size is known.

4. Appending Strings (append())

StringBuffer sb = new StringBuffer("Java");
sb.append(" Selenium");
System.out.println(sb);

Explanation

  • Modifies the same object.
  • No new object created.
  • Output: Java Selenium

5. Appending Different Data Types

StringBuffer sb = new StringBuffer("Count: ");
sb.append(10);
sb.append(true);
System.out.println(sb);

Explanation

  • Supports int, boolean, char, double, etc.
  • Output: Count: 10true

6. Inserting Text (insert())

StringBuffer sb = new StringBuffer("Java");
sb.insert(4, " Selenium");
System.out.println(sb);

Explanation

  • Inserts at specified index.
  • Output: Java Selenium

7. Deleting Characters (delete())

StringBuffer sb = new StringBuffer("Java Selenium");
sb.delete(4, 13);
System.out.println(sb);

Explanation

  • Deletes substring between indices.
  • Output: Java

8. Deleting Single Character (deleteCharAt())

StringBuffer sb = new StringBuffer("Javva");
sb.deleteCharAt(3);
System.out.println(sb);

Explanation

  • Removes character at index.
  • Output: Java

9. Reversing String (reverse())

StringBuffer sb = new StringBuffer("Java");
sb.reverse();
System.out.println(sb);

Explanation

  • Reverses characters in place.
  • Output: avaJ

10. Replacing Substring (replace())

StringBuffer sb = new StringBuffer("Java Automation");
sb.replace(5, 15, "Selenium");
System.out.println(sb);

Explanation

  • Replaces characters between indices.
  • Output: Java Selenium

11. Finding Length

StringBuffer sb = new StringBuffer("Java");
System.out.println(sb.length());

Explanation

  • Returns number of characters.
  • Output: 4

12. Finding Capacity

StringBuffer sb = new StringBuffer("Java");
System.out.println(sb.capacity());

Explanation

  • Capacity = 16 + length of initial string.
  • Output: 20

13. Ensuring Capacity (ensureCapacity())

StringBuffer sb = new StringBuffer();
sb.ensureCapacity(50);
System.out.println(sb.capacity());

Explanation

  • Ensures minimum capacity.
  • Avoids frequent resizing.

14. Character Access (charAt())

StringBuffer sb = new StringBuffer("Java");
System.out.println(sb.charAt(1));

Explanation

  • Index-based character access.
  • Output: a

15. Setting Character (setCharAt())

StringBuffer sb = new StringBuffer("Java");
sb.setCharAt(1, 'o');
System.out.println(sb);

Explanation

  • Modifies character at index.
  • Output: Jova

16. Converting StringBuffer to String

StringBuffer sb = new StringBuffer("Java");
String s = sb.toString();
System.out.println(s);

Explanation

  • Creates immutable String.
  • Common when returning values.

17. String Immutability vs StringBuffer Mutability

String s = "Java";
s.concat(" Selenium");
System.out.println(s);
StringBuffer sb = new StringBuffer("Java");
sb.append(" Selenium");
System.out.println(sb);

Explanation

  • String remains unchanged.
  • StringBuffer changes in place.
  • Output:
  • ○ Java
  • ○ Java Selenium

18. Thread Safety Demonstration (Conceptual)

StringBuffer sb = new StringBuffer("Test");
sb.append(" Safe");

Explanation

  • All methods are synchronized.
  • Safe for multi-threaded environments.
  • Slower than StringBuilder.

19. Using StringBuffer in Loop (Performance Friendly)

StringBuffer sb = new StringBuffer();
for (int i = 1; i <= 5; i++) {
sb.append(i);
}
System.out.println(sb);

Explanation

  • Avoids multiple String objects.
  • Output: 12345

20. Comparing StringBuffer Objects

StringBuffer sb1 = new StringBuffer("Java");
StringBuffer sb2 = new StringBuffer("Java");
System.out.println(sb1.equals(sb2));

Explanation

  • equals() not overridden.
  • Compares references.
  • Output: false

21. Correct Way to Compare StringBuffer Content

StringBuffer sb1 = new StringBuffer("Java");
StringBuffer sb2 = new StringBuffer("Java");
System.out.println(sb1.toString().equals(sb2.toString()));

Explanation

  • Convert to String for content comparison.
  • Output: true

22. StringBuffer with Null Handling

StringBuffer sb = new StringBuffer();
sb.append((String) null);
System.out.println(sb);

Explanation

  • Appends literal "null".
  • Output: null

23. StringBuffer Substring

StringBuffer sb = new StringBuffer("Automation");
String sub = sb.substring(0, 4);
System.out.println(sub);

Explanation

  • Returns a String, not StringBuffer.
  • Output: Auto

24. Clearing a StringBuffer

StringBuffer sb = new StringBuffer("Java");
sb.setLength(0);
System.out.println(sb.length());

Explanation

  • Clears content.
  • Output: 0

25. Interview Summary Example (StringBuffer)

StringBuffer sb = new StringBuffer("Java");
sb.append(" Test");
System.out.println(sb);

Explanation

  • Demonstrates:
  • ○ Mutability
  • ○ Heap storage
  • ○ Thread safety
  • Very common interview discussion topic.