StringBuilder and StringBuffer

Master mutable strings in Java for efficient text manipulation and better performance.

Why StringBuilder and StringBuffer?

Remember that String objects in Java are immutable (cannot be changed). Every time you modify a String, Java creates a new object in memory. This is inefficient when you need to perform many modifications.

StringBuilder and StringBuffer solve this problem. They are mutable, meaning you can modify them without creating new objects every time. This makes them much faster for operations like concatenation in loops.

  • Both StringBuilder and StringBuffer are mutable (can be changed)
  • More efficient than String for multiple modifications
  • Perfect for building strings dynamically in loops
  • Reduce memory overhead and improve performance

💡 Key Difference: StringBuilder is faster but not thread-safe. StringBuffer is thread-safe but slightly slower. For single-threaded applications, use StringBuilder.

String vs StringBuilder Performance

Let's see why StringBuilder is more efficient than regular String concatenation.

Example: Performance Comparison

public class StringVsBuilder {
    public static void main(String[] args) {
        // Using String (inefficient - creates many objects)
        long startTime = System.currentTimeMillis();
        String str = "";
        for (int i = 0; i < 10000; i++) {
            str += "Hello";  // Creates new object each time
        }
        long endTime = System.currentTimeMillis();
        System.out.println("String time: " + (endTime - startTime) + "ms");
        
        // Using StringBuilder (efficient - modifies same object)
        startTime = System.currentTimeMillis();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 10000; i++) {
            sb.append("Hello");  // Modifies existing object
        }
        endTime = System.currentTimeMillis();
        System.out.println("StringBuilder time: " + (endTime - startTime) + "ms");
    }
}
Output:
String time: 156ms
StringBuilder time: 2ms

Explanation:

  • String concatenation in loops creates thousands of temporary objects
  • StringBuilder modifies the same object, avoiding memory waste
  • StringBuilder can be 50-100x faster for multiple concatenations

Creating StringBuilder Objects

You can create StringBuilder objects in different ways depending on your needs.

Example: Different Ways to Create StringBuilder

public class CreateStringBuilder {
    public static void main(String[] args) {
        // Method 1: Empty StringBuilder (default capacity 16)
        StringBuilder sb1 = new StringBuilder();
        System.out.println("Empty capacity: " + sb1.capacity());
        
        // Method 2: With initial capacity
        StringBuilder sb2 = new StringBuilder(50);
        System.out.println("Custom capacity: " + sb2.capacity());
        
        // Method 3: With initial string
        StringBuilder sb3 = new StringBuilder("Hello");
        System.out.println("With string: " + sb3);
        System.out.println("Length: " + sb3.length());
        
        // StringBuffer (similar syntax, thread-safe)
        StringBuffer sbf = new StringBuffer("Java");
        System.out.println("StringBuffer: " + sbf);
    }
}
Output:
Empty capacity: 16
Custom capacity: 50
With string: Hello
Length: 5
StringBuffer: Java

Explanation:

  • new StringBuilder() - Creates empty builder with default capacity of 16 characters
  • new StringBuilder(50) - Creates with specific capacity for better performance
  • new StringBuilder("Hello") - Initializes with existing string
  • capacity() returns allocated space, length() returns actual content size

Essential StringBuilder Methods

1. append() - Add to End

Adds string, number, or character to the end of the StringBuilder.

Example: sb.append("Hello") adds "Hello" at the end

2. insert() - Add at Position

Inserts content at a specific index position.

Example: sb.insert(5, "World") inserts "World" at index 5

3. delete() - Remove Characters

Removes characters from start index to end index.

Example: sb.delete(0, 5) removes first 5 characters

4. reverse() - Reverse String

Reverses the entire character sequence.

Example: sb.reverse() reverses "Hello" to "olleH"

5. replace() - Replace Portion

Replaces characters from start index to end index with new string.

Example: sb.replace(0, 5, "Hi") replaces first 5 chars with "Hi"

6. toString() - Convert to String

Converts StringBuilder to regular String object.

Example: String result = sb.toString()

StringBuilder Methods in Action

Let's explore the most commonly used StringBuilder methods with practical examples.

Example: Working with StringBuilder Methods

public class StringBuilderMethods {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("Java");
        System.out.println("Original: " + sb);
        
        // append() - Add to end
        sb.append(" Programming");
        System.out.println("After append: " + sb);
        
        // insert() - Add at position
        sb.insert(4, " 17");
        System.out.println("After insert: " + sb);
        
        // replace() - Replace portion
        sb.replace(0, 4, "Python");
        System.out.println("After replace: " + sb);
        
        // delete() - Remove characters
        sb.delete(6, 9);
        System.out.println("After delete: " + sb);
        
        // reverse() - Reverse string
        sb.reverse();
        System.out.println("After reverse: " + sb);
        
        // Convert back to String
        String result = sb.toString();
        System.out.println("Final String: " + result);
    }
}
Output:
Original: Java
After append: Java Programming
After insert: Java 17 Programming
After replace: Python 17 Programming
After delete: Python Programming
After reverse: gnimmargorP nohtyP
Final String: gnimmargorP nohtyP

Explanation:

  • All methods modify the same StringBuilder object (no new objects created)
  • insert(4, " 17") adds " 17" at index 4
  • delete(6, 9) removes characters from index 6 to 8 (end is exclusive)
  • toString() converts StringBuilder to regular String when needed

More StringBuilder Methods

Explore additional useful methods for string manipulation.

Example: Additional Methods

public class MoreMethods {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("Hello World");
        
        // charAt() - Get character at index
        System.out.println("Character at 6: " + sb.charAt(6));
        
        // setCharAt() - Change character at index
        sb.setCharAt(6, 'J');
        System.out.println("After setCharAt: " + sb);
        
        // deleteCharAt() - Remove character at index
        sb.deleteCharAt(5);
        System.out.println("After deleteCharAt: " + sb);
        
        // substring() - Extract portion (doesn't modify)
        String sub = sb.substring(0, 5);
        System.out.println("Substring: " + sub);
        System.out.println("Original unchanged: " + sb);
        
        // length() and capacity()
        System.out.println("Length: " + sb.length());
        System.out.println("Capacity: " + sb.capacity());
        
        // setLength() - Truncate or extend
        sb.setLength(5);
        System.out.println("After setLength(5): " + sb);
    }
}
Output:
Character at 6: W
After setCharAt: Hello Jorld
After deleteCharAt: HelloJorld
Substring: Hello
Original unchanged: HelloJorld
Length: 10
Capacity: 27
After setLength(5): Hello

Explanation:

  • setCharAt(6, 'J') replaces character at index 6 with 'J'
  • deleteCharAt(5) removes single character at index 5
  • substring() extracts but doesn't modify the StringBuilder
  • setLength(5) truncates to 5 characters or extends with null chars

StringBuilder vs StringBuffer

Both classes have identical methods but differ in thread-safety and performance.

Example: StringBuilder vs StringBuffer

public class BuilderVsBuffer {
    public static void main(String[] args) {
        // StringBuilder (not thread-safe, faster)
        StringBuilder builder = new StringBuilder("Java");
        builder.append(" is");
        builder.append(" awesome");
        System.out.println("StringBuilder: " + builder);
        
        // StringBuffer (thread-safe, slightly slower)
        StringBuffer buffer = new StringBuffer("Python");
        buffer.append(" is");
        buffer.append(" cool");
        System.out.println("StringBuffer: " + buffer);
        
        // Both have same methods
        builder.reverse();
        buffer.reverse();
        System.out.println("Reversed StringBuilder: " + builder);
        System.out.println("Reversed StringBuffer: " + buffer);
    }
}
Output:
StringBuilder: Java is awesome
StringBuffer: Python is cool
Reversed StringBuilder: emosewa si avaJ
Reversed StringBuffer: looc si nohtyP

Explanation:

  • Both have identical API and methods
  • StringBuilder is faster for single-threaded applications
  • StringBuffer has synchronized methods for thread safety
  • Use StringBuilder unless you need thread-safety

Practical Use Case: Building Dynamic Text

A real-world example showing when to use StringBuilder over String concatenation.

Example: Creating HTML Table Dynamically

public class DynamicHTML {
    public static void main(String[] args) {
        String[] students = {"Alice", "Bob", "Charlie"};
        int[] marks = {85, 92, 78};
        
        // Using StringBuilder to build HTML efficiently
        StringBuilder html = new StringBuilder();
        html.append("\n");
        html.append("  \n");
        
        for (int i = 0; i < students.length; i++) {
            html.append("  ");
            html.append("");
            html.append("");
            html.append("\n");
        }
        
        html.append("
NameMarks
").append(students[i]).append("").append(marks[i]).append("
"); System.out.println(html.toString()); } }
Output:
<table>
  <tr><th>Name</th><th>Marks</th></tr>
  <tr><td>Alice</td><td>85</td></tr>
  <tr><td>Bob</td><td>92</td></tr>
  <tr><td>Charlie</td><td>78</td></tr>
</table>

Explanation:

  • StringBuilder is perfect for building complex strings in loops
  • Method chaining: append().append().append() makes code concise
  • Much more efficient than string concatenation for dynamic content
  • Common use cases: HTML generation, CSV creation, log messages

When to Use Each Type

Use String When:

Working with fixed text that won't change, or performing only 1-2 concatenations.

Examples: Configuration values, displaying static messages, storing names

Use StringBuilder When:

Building strings dynamically in single-threaded applications (most common case).

Examples: Loops with concatenation, dynamic HTML/XML, building queries

Use StringBuffer When:

Building strings in multi-threaded environments where thread safety is required.

Examples: Shared data between threads, concurrent string operations

Key Points to Remember

  • Mutability: StringBuilder and StringBuffer can be modified, String cannot
  • Performance: StringBuilder is fastest, StringBuffer is thread-safe but slower, String is slowest for multiple modifications
  • Default choice: Use StringBuilder for dynamic string building in loops
  • Conversion: Use toString() to convert StringBuilder/StringBuffer back to String
  • Capacity: Automatically grows when needed, but setting initial capacity improves performance
  • Method chaining: Most methods return the same object, allowing chained calls

🎯 Best Practice: Always use StringBuilder when concatenating strings in a loop. It can improve performance by 50-100x compared to regular String concatenation!