Skip to content
Theory · Strings · lesson 7 of 11

StringBuilder

A string cannot be changed. But what if the text has to be built piece by piece, in a loop for example? Every + creates a new string:

JAVA
public class Main {
    public static void main(String[] args) {
        String s = "";
        for (int i = 0; i < 5; i++) {
            s = s + i;
        }
        System.out.println(s); // 01234
    }
}

The program works and prints 01234. But let's look at what happens on each lap of the loop:

  1. On the first lap, s + i creates a new string 0.
  2. On the second, a new string 01: the old character is copied into it and the new one is added.
  3. On the third, a string 012, and all the earlier characters are copied again.
  4. And so on to the end: every lap makes a new card and copies all the text gathered so far onto it.

If each lap adds one character, then on lap 100 Java copies out 100 characters, and on lap 10,000 it copies out 10,000. Over 10,000 laps that adds up to 1 + 2 + … + 10,000, that is, about 50 million characters, even though the finished string holds only 10,000. The longer the text, the more each next lap costs. Why + in a loop is slow is a frequent interview question.

Imagine a draft. You cannot correct anything on a card, but on a draft you can add, insert and erase as much as you like. When the text is ready, it is copied cleanly onto a card. In Java, such a draft is called StringBuilder.

The StringBuilder draft

StringBuilder holds a changeable sequence of characters. Its methods change the draft itself and do not create a new one:

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

Line by line:

  1. new StringBuilder() creates an empty draft. The word new creates a new object.
  2. sb.append(i) adds the number to the end of the draft. No new string is created.
  3. sb.toString() makes the clean copy: it returns an ordinary String.
  4. println(result) prints 01234.

When the text no longer fits, the draft takes more room for itself, with some to spare. That is why a lap usually adds only the new character, and the whole text is moved only now and then, when the draft grows.

The draft picture is off here. A paper draft is usually thrown away once the clean copy is made. A StringBuilder does not disappear after toString(): you can keep changing it, and the string you already got does not change.

The draft's methods

JAVA
StringBuilder sb = new StringBuilder("Java");
sb.append("!").insert(0, "Hi, ");
System.out.println(sb);          // Hi, Java!
System.out.println(sb.length()); // 9
sb.reverse();
System.out.println(sb);          // !avaJ ,iH

Let's take the methods one by one:

  • append("!") adds a value to the end: Java!;
  • insert(0, "Hi, ") inserts text before index 0, that is, at the start: Hi, Java!;
  • length() returns the length, as for a string;
  • reverse() turns the text back to front.

Note two things:

  • append, insert and reverse return the same draft. That is why calls can be written as a chain: in sb.append("!").insert(0, "Hi, "), append runs first, then insert on the same sb. The chain runs left to right.
  • sb.reverse(); changed sb without any assignment. A string method would return a new string, while a StringBuilder method changes the draft itself.

println(sb) prints the draft's text: println calls toString() on it by itself.

StringBuilder or +

When to choose which:

  • leave joining in one expression, such as "Hi, " + name + "!", to +: Java builds such a string in one go;
  • build text that is put together in a loop in a StringBuilder.

In an interview, a second question often follows: how StringBuilder differs from StringBuffer. Their methods are the same. But StringBuffer is protected for the case when several threads work with it at once—parts of a program that run in parallel. That protection costs speed, so ordinary code uses StringBuilder.

Common mistake

The draft is put into a variable of type String:

JAVA
StringBuilder sb = new StringBuilder("Hi");
sb.append("!");
String text = sb; // ✗
TEXT
error: incompatible types: StringBuilder cannot be converted to String

The program does not compile: StringBuilder and String are different types, and the draft does not turn into a string by itself. Make the clean copy: String text = sb.toString();.

Key points

  • + in a loop creates a new string every time and copies all the text gathered so far.
  • StringBuilder is a changeable draft: append, insert and reverse change it in place and return it.
  • Calls to StringBuilder methods can be chained; they run left to right.
  • The finished string comes from toString(); ordinary code uses StringBuilder, not StringBuffer.