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:
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:
- On the first lap,
s + icreates a new string0. - On the second, a new string
01: the old character is copied into it and the new one is added. - On the third, a string
012, and all the earlier characters are copied again. - 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:
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 5; i++) {
sb.append(i);
}
String result = sb.toString();
System.out.println(result); // 01234Line by line:
new StringBuilder()creates an empty draft. The wordnewcreates a new object.sb.append(i)adds the number to the end of the draft. No new string is created.sb.toString()makes the clean copy: it returns an ordinaryString.println(result)prints01234.
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
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 ,iHLet's take the methods one by one:
append("!")adds a value to the end:Java!;insert(0, "Hi, ")inserts text before index0, 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,insertandreversereturn the same draft. That is why calls can be written as a chain: insb.append("!").insert(0, "Hi, "),appendruns first, theninserton the samesb. The chain runs left to right.sb.reverse();changedsbwithout any assignment. A string method would return a new string, while aStringBuildermethod 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:
StringBuilder sb = new StringBuilder("Hi");
sb.append("!");
String text = sb; // ✗error: incompatible types: StringBuilder cannot be converted to StringThe 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.StringBuilderis a changeable draft:append,insertandreversechange it in place and return it.- Calls to
StringBuildermethods can be chained; they run left to right. - The finished string comes from
toString(); ordinary code usesStringBuilder, notStringBuffer.