00:00

StringBuilder Class in Java – Fast, Mutable Strings

StringBuilder is a mutable sequence of characters, added in Java 5 as a faster, unsynchronized alternative to StringBuffer. It is the standard tool for building strings piece by piece: in loops, when generating CSV, JSON or HTML, or whenever many modifications are needed. The compiler itself uses similar techniques for the + operator.

This tutorial covers building strings with StringBuilder, its key methods, capacity, comparison pitfalls, and how it compares with String and StringBuffer.

1. Building a String Step by Step

BuildCsv.java
import java.util.List;

public class BuildCsv {
    record Employee(String name, String dept, double salary) { }

    public static void main(String[] args) {
        List<Employee> staff = List.of(new Employee("Asha", "Backend", 120000),
                                       new Employee("Ravi", "Frontend", 95000),
                                       new Employee("Meera", "Data", 130000));

        StringBuilder csv = new StringBuilder(128);          // pre-size when you can estimate
        csv.append("name,dept,salary\n");
        for (Employee e : staff) {
            csv.append(e.name()).append(',')
               .append(e.dept()).append(',')
               .append(e.salary()).append('\n');               // chaining
        }
        System.out.print(csv);
        System.out.println("characters: " + csv.length());
    }
}
Output
name,dept,salary
Asha,Backend,120000.0
Ravi,Frontend,95000.0
Meera,Data,130000.0
characters: 81

append returns the same builder, so calls chain naturally. Call toString() (or pass the builder where a CharSequence is accepted, as print does) to get the result.

2. Key Methods

BuilderMethods.java
public class BuilderMethods {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("racecar level noon");
        System.out.println("reverse()      : " + new StringBuilder("Java").reverse());
        System.out.println("insert(0, \">\") : " + new StringBuilder("menu").insert(0, "> "));
        sb.replace(0, 7, "kayak");
        System.out.println("replace        : " + sb);
        sb.delete(5, 11);
        System.out.println("delete         : " + sb);
        sb.setLength(0);                                  // clear and reuse
        System.out.println("after setLength(0), isEmpty(): " + sb.isEmpty());

        String word = "madam";
        boolean palindrome = new StringBuilder(word).reverse().toString().equals(word);
        System.out.println(word + " is a palindrome: " + palindrome);

        StringBuilder a = new StringBuilder("abc"), b = new StringBuilder("abc");
        System.out.println("a.equals(b)        : " + a.equals(b));               // identity!
        System.out.println("a.compareTo(b) == 0: " + (a.compareTo(b) == 0));     // Java 11
        System.out.println("contentEquals      : " + "abc".contentEquals(a));
    }
}
Output
reverse()      : avaJ
insert(0, ">") : > menu
replace        : kayak level noon
delete         : kayak noon
after setLength(0), isEmpty(): true
madam is a palindrome: true
a.equals(b)        : false
a.compareTo(b) == 0: true
contentEquals      : true
MethodPurpose
append(x)Add a value of any type at the end
insert(i, x)Insert at an index
replace(start, end, s)Replace a range
delete(start, end), deleteCharAt(i)Remove characters
reverse()Reverse in place (handles surrogate pairs correctly)
setLength(n)Truncate, or clear with setLength(0) to reuse the builder
charAt, setCharAt, indexOf, substringRead, write and search
capacity(), ensureCapacity(), trimToSize()Manage the internal buffer
compareTo() (11), isEmpty() (15), repeat() (21)Newer conveniences

Pitfall: StringBuilder does not override equals(), so two builders with the same text are not equal. Compare with compareTo, String.contentEquals, or their toString() values.

3. Capacity

Like StringBuffer, a builder starts with a capacity of 16 (or 16 + initial text length) and grows to (old × 2 + 2) when needed, copying its contents. If you can estimate the final size, pass it to the constructor, as new StringBuilder(128) above, to avoid repeated copying. See StringBuffer for a capacity demonstration.

4. Performance: String vs StringBuffer vs StringBuilder

PerformanceCompare.java
public class PerformanceCompare {
    static long time(Runnable r) {
        long start = System.nanoTime();
        r.run();
        return (System.nanoTime() - start) / 1_000_000;
    }

    public static void main(String[] args) {
        int n = 50_000;
        long concat = time(() -> { String s = ""; for (int i = 0; i < n; i++) s += i % 10; });
        long buffer = time(() -> { StringBuffer s = new StringBuffer(); for (int i = 0; i < n; i++) s.append(i % 10); });
        long builder = time(() -> { StringBuilder s = new StringBuilder(); for (int i = 0; i < n; i++) s.append(i % 10); });
        System.out.println("String += is the slowest: " + (concat > buffer && concat > builder));
        System.out.printf("String +=      %5d ms%nStringBuffer   %5d ms%nStringBuilder  %5d ms%n", concat, buffer, builder);
    }
}
Output (sample run; timings vary by machine)
String += is the slowest: true
String +=         83 ms
StringBuffer       1 ms
StringBuilder      0 ms

Repeated += copies the whole string on every iteration (quadratic time). Both builders append in place; StringBuilder avoids synchronization overhead as well.

AspectStringStringBufferStringBuilder
MutableNoYesYes
SynchronizedNot neededYesNo
Speed for repeated changesSlowFastFastest
Use whenValue does not changeOne instance shared across threadsBuilding strings in one thread (most cases)

5. When to Use StringBuilder

  • Concatenating inside loops.
  • Building text conditionally across several statements.
  • Manipulating characters: reversing, inserting, deleting.

You do not need it for a single expression like "Hello " + name + "!"; the compiler optimises that. For joining with separators, StringJoiner, String.join or Collectors.joining are clearer.

6. Summary

  • StringBuilder is a mutable, unsynchronized character sequence for efficient string building.
  • Use append, insert, replace, delete and reverse, then toString().
  • It does not override equals; compare contents explicitly.
  • Prefer it over += in loops and over StringBuffer unless an instance is shared between threads.

Related Tutorials