StringBuilder

Su Suriya Ravichandran Updated 14 Nov 2026
5 min read ·Lesson 100 of 133

StringBuilder is a mutable sequence of characters. Unlike String, whose content can never change, a StringBuilder can be appended to, inserted into, edited, and shortened in place. It exists to build text efficiently, especially when the text is assembled piece by piece in a loop, and then converted to a String once at the end with toString().

Why StringBuilder Exists

Because strings are immutable, building text with += in a loop creates a new string on every iteration and copies everything accumulated so far:

String result = "";
for (int i = 0; i < 5; i++) {
    result += i;        // "0", "01", "012", "0123", "01234": five separate strings
}

For n pieces, the total copying grows roughly with n². For a few pieces nobody notices; for thousands, it becomes a real slowdown and a lot of garbage for the collector.

A StringBuilder keeps one internal character buffer and grows it only when needed:

StringBuilder sb = new StringBuilder();
for (int i = 0; i < 5; i++) {
    sb.append(i);
}
String result = sb.toString();       // "01234"

Each append writes into the existing buffer, so the total work grows linearly with the length of the result.

Creating a StringBuilder

StringBuilder a = new StringBuilder();            // empty, initial capacity 16
StringBuilder b = new StringBuilder("Hello");     // starts with text
StringBuilder c = new StringBuilder(1000);        // empty, capacity 1000

Capacity is the size of the internal buffer; length is the number of characters actually stored. When the length would exceed the capacity, the buffer is reallocated larger (roughly doubling) and the content copied. If you know the approximate final size, passing it to the constructor avoids those reallocations.

Appending

append is overloaded for every primitive type, String, char[], CharSequence, and Object, and it returns the builder itself, so calls chain:

StringBuilder sb = new StringBuilder();
sb.append("Order #").append(1042)
  .append(": ").append(3).append(" x ")
  .append(499.5).append(' ')
  .append(true);
System.out.println(sb);       // Order #1042: 3 x 499.5 true

Appending null adds the four characters null, just as string concatenation does.

Editing Methods

MethodEffect
insert(index, value)Insert at a position, shifting the rest right
delete(start, end)Remove characters from start up to (not including) end
deleteCharAt(index)Remove one character
replace(start, end, str)Replace a range with new text
setCharAt(index, ch)Overwrite one character
reverse()Reverse the sequence (keeps surrogate pairs intact)
setLength(n)Truncate to n characters, or pad with '\u0000'
StringBuilder sb = new StringBuilder("Hello World");
sb.insert(5, ",");              // "Hello, World"
sb.append('!');                 // "Hello, World!"
sb.replace(7, 12, "Java");      // "Hello, Java!"
sb.deleteCharAt(sb.length() - 1).reverse();   // "avaJ ,olleH"
sb.setLength(0);                // "" : quick way to reuse a builder

All of these modify the builder in place and return it. Indexes follow the same rules as String: zero-based, with exclusive end indexes, and StringIndexOutOfBoundsException outside the valid range.

Reading Methods

StringBuilder shares many read-only methods with String:

StringBuilder d = new StringBuilder("abc");
d.setCharAt(1, 'X');            // "aXc"
d.length();                     // 3
d.charAt(0);                    // 'a'
d.indexOf("c");                 // 2
d.substring(1);                 // "Xc" (returns a String)
d.isEmpty();                    // false (Java 15+)

It implements CharSequence, so it can be passed to any method that accepts one, such as String.join, Pattern.matcher, or String.contentEquals.

Converting to a String

String text = sb.toString();

toString() copies the current content into a new, independent String. Later changes to the builder do not affect strings already produced.

Comparing Builders

StringBuilder does not override equals, so equals compares object identity:

StringBuilder a = new StringBuilder("x");
StringBuilder b = new StringBuilder("x");

a.equals(b);                                // false: different objects
a.compareTo(b) == 0;                        // true: compareTo (Java 11+) compares content
a.toString().equals(b.toString());          // true
"x".contentEquals(a);                       // true

For the same reason, do not use a StringBuilder as a HashMap key or put it in a HashSet: its content can change, and it does not define value equality.

When to Use StringBuilder

SituationUse
Building text inside a loopStringBuilder
Assembling text across several methods (passing the builder along)StringBuilder
Many inserts, deletes, or character editsStringBuilder
A single expression joining a few values+ (the compiler optimizes it)
Joining a collection with a separatorString.join, StringJoiner, Collectors.joining
Fixed layout with padding and decimalsString.format (or formatted)

StringBuilder is not thread-safe

StringBuilder has no synchronization. A single builder must not be modified by multiple threads at once. In practice this is rarely a limitation: builders are almost always local variables used by one thread. StringBuffer, covered in the next lesson, is the synchronized alternative.

Practical Example: Building an HTML Table

Generating HTML, CSV, SQL, or any structured text is a typical use: many small pieces appended in loops.

import java.util.*;

public class SbDemo {
    record Row(String course, int enrolled, double rating) { }

    static String escape(String s) {
        StringBuilder sb = new StringBuilder(s.length());
        for (char c : s.toCharArray()) {
            switch (c) {
                case '<' -> sb.append("<");
                case '>' -> sb.append(">");
                case '&' -> sb.append("&");
                case '"' -> sb.append(""");
                default -> sb.append(c);
            }
        }
        return sb.toString();
    }

    static String htmlTable(List<Row> rows) {
        StringBuilder html = new StringBuilder(256);
        html.append("<table>\n  <tr><th>Course</th><th>Enrolled</th><th>Rating</th></tr>\n");
        for (Row r : rows) {
            html.append("  <tr><td>").append(escape(r.course()))
                .append("</td><td>").append(r.enrolled())
                .append("</td><td>").append(r.rating())
                .append("</td></tr>\n");
        }
        return html.append("</table>").toString();
    }

    public static void main(String[] args) {
        System.out.println(htmlTable(List.of(
            new Row("Java Basics", 1250, 4.7),
            new Row("C & C++ <Advanced>", 430, 4.5))));
    }
}

Output:

<table>
  <tr><th>Course</th><th>Enrolled</th><th>Rating</th></tr>
  <tr><td>Java Basics</td><td>1250</td><td>4.7</td></tr>
  <tr><td>C & C++ <Advanced></td><td>430</td><td>4.5</td></tr>
</table>

Two builders do the work. escape walks through a course name and appends either the character itself or its HTML entity, so a title containing < or & cannot break the page or inject markup; sizing the builder with s.length() avoids most reallocations. htmlTable builds the whole table with chained append calls, appending numbers directly without converting them first, and converts to a String exactly once at the end. The same pattern, a builder plus an escaping function for untrusted values, applies when generating CSV, JSON, or XML by hand, although real projects usually use a template engine or library for HTML and JSON.

0 Comments

Reviewed before they appear

No comments yet.

Java
Java Introduction Java Features Java Syntax Java Comments Java Statements Java Output Java Variables Java Data Types Java Type Casting Java Operators Java Strings Java Numbers Java Math Java Booleans Java User Input Java Conditions Java If Else Java Switch Java While Loop Java For Loop Java Break Java Continue Java Arrays Java Methods Java Parameters Java Return Values Java Scope Java Recursion Install Java Install JDK Java IDEs Java JDK Java JRE Java JVM Java Compiler Java File Compile Java Run Java JShell Basics Java Packages Java OOP Java Classes Java Objects Class Methods Constructors Constructor Overload this Keyword static Keyword final Keyword Encapsulation Inheritance Polymorphism Abstraction Access Modifiers super Keyword Method Overload Method Override Instanceof Operator Nested Classes Inner Classes Anonymous Classes Enums Records Array Basics Array Length Loop Arrays Multidimensional Arrays Array Copy Array Sorting Array Search ArrayList LinkedList HashSet TreeSet HashMap TreeMap Queue Interface Deque Interface Stack Class Iterator List Interface Set Interface Map Interface Collections Class Comparable Comparator Generics Basics Generic Classes Generic Methods Wildcards String Basics String Length String Methods String Concatenation String Compare String Search String Replace String Split String Format StringBuilder StringBuffer Text Blocks Regular Expressions Number Types Integer Class Float Class Double Class BigInteger BigDecimal Math Class Random Numbers Number Format Date Basics LocalDate LocalTime LocalDateTime ZonedDateTime Date Formatting Date Parsing Period Class Duration Class Java Instant Class Java Exception Basics Java try...catch Java Multiple Catch Blocks Java finally Block Java throw Keyword Java throws Keyword Java Checked Exceptions Java Unchecked Exceptions Java Custom Exceptions Java try-with-resources Java Exception Chaining
Ask about this post
AI Ask about this post

Ask questions about StringBuilder and get answers drawn from it.

Signed-in readers only.