String vs StringBuilder vs StringBuffer in Java
Introduction
Because a
(Note - This tutorial builds on Java String Basics and ImmutabilityClick to read tutorial: Java String Basics and Why Strings Are Immutable.) The problem with joining strings in a loop
(For a single expression such as
OUTPUT of the above code
Useful StringBuilder methods
OUTPUT of the above code
Explanation of the code
OUTPUT of the above code (timings vary from machine to machine)
Both produced the same 238,890-character string, but the
StringBuffer - the thread-safe version
StringBuffer has the same methods as
OUTPUT of the above code
Capacity is the size of the internal buffer, which grows automatically. If you know roughly how long the final text will be,
Rule of thumb: use
String can never be changed, every "change" creates a new object. That is fine for a few joins, but building a long string piece by piece - in a loop, say - creates thousands of throwaway objects. Java has two classes made for building text: StringBuilder and StringBuffer. This tutorial explains String vs StringBuilder vs StringBuffer in Java. We will start with the problem of joining strings in a loop. We will then use StringBuilder and its most useful methods - append(), insert(), delete(), reverse() and more. Next we will measure the speed difference. Lastly, we will see how StringBuffer differs, and compare all three classes side by side.(Note - This tutorial builds on Java String Basics and ImmutabilityClick to read tutorial: Java String Basics and Why Strings Are Immutable.) The problem with joining strings in a loop
result = result + piece; does not add to the existing string. It creates a new String, copies all the characters of result into it, then adds piece. In a loop, each copy is longer than the last - so building a string of n pieces copies roughly n²/2 characters in total. For a few pieces nobody notices; for tens of thousands, it becomes very slow.(For a single expression such as
"Hello, " + name + "!", the compiler already generates efficient code, so + is the right choice there. The problem is only += repeated in a loop.)
StringBuilder - a mutable string
A StringBuilder holds a mutable sequence of characters in an internal buffer, which grows as needed. Its methods change that buffer directly, without creating new objects, and most of them return the same StringBuilder, so calls can be chained. When the text is complete, toString() creates the final String.
Building a string with StringBuilder
//BuilderBasics.java
public class BuilderBasics {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= 5; i++) {
sb.append(i);
if (i < 5) {
sb.append(", ");
}
}
String numbers = sb.toString();
System.out.println(numbers);
String receipt = new StringBuilder()
.append("Item: ").append("Java book")
.append(" | Qty: ").append(2)
.append(" | Paid: ").append(true)
.toString();
System.out.println(receipt);
}
}
1, 2, 3, 4, 5 Item: Java book | Qty: 2 | Paid: true
append() accepts any type - strings, numbers, characters, booleans and objects - and converts it to text, just like +.
append(x)- addsxto the end.insert(index, x)- insertsxatindex.delete(start, end)anddeleteCharAt(index)- remove characters.replace(start, end, str)- replaces a range of characters.reverse()- reverses the characters.setCharAt(index, ch),charAt(index),length(),indexOf(str)- work like theirStringversions.setLength(n)- cuts the text toncharacters;setLength(0)empties the builder so it can be reused.
StringBuilder methods
//BuilderMethods.java
public class BuilderMethods {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("Hello World");
sb.insert(5, ",");
System.out.println("insert : " + sb);
sb.append("!");
System.out.println("append : " + sb);
sb.replace(7, 12, "Java");
System.out.println("replace : " + sb);
sb.delete(5, 6);
System.out.println("delete : " + sb);
sb.setCharAt(0, 'J');
System.out.println("setCharAt : " + sb);
sb.deleteCharAt(sb.length() - 1);
System.out.println("deleteCharAt: " + sb + " (length " + sb.length() + ")");
sb.reverse();
System.out.println("reverse : " + sb);
sb.setLength(0);
System.out.println("setLength(0): [" + sb + "]");
String word = "racecar";
boolean palindrome = new StringBuilder(word).reverse().toString().equals(word);
System.out.println(word + " is a palindrome: " + palindrome);
}
}
insert : Hello, World append : Hello, World! replace : Hello, Java! delete : Hello Java! setCharAt : Jello Java! deleteCharAt: Jello Java (length 10) reverse : avaJ olleJ setLength(0): [] racecar is a palindrome: true
- Every method changed the same
sbobject, step by step. Ranges work likesubstring()-startis included andendis not. - Printing a
StringBuildercalls itstoString(), soprintln(sb)shows its current text. new StringBuilder(word).reverse().toString()is the classic one-line way to reverse a string, sinceStringhas noreverse()method.- Compare with
toString():StringBuilderdoes not overrideequals(), so two builders with the same text are notequals(). Convert toStringfirst, as explained in == vs equals() vs compareTo()Click to read tutorial: Java String Comparison: == vs equals() vs compareTo().
+= on a String and once with a StringBuilder.
String += vs StringBuilder in a loop
//ConcatTiming.java
public class ConcatTiming {
public static void main(String[] args) {
int n = 50_000;
long start = System.nanoTime();
String s = "";
for (int i = 0; i < n; i++) {
s += i;
}
long stringMillis = (System.nanoTime() - start) / 1_000_000;
start = System.nanoTime();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
sb.append(i);
}
String built = sb.toString();
long builderMillis = (System.nanoTime() - start) / 1_000_000;
System.out.println("Same result: " + s.equals(built) + ", length " + built.length());
System.out.println("String += : " + stringMillis + " ms");
System.out.println("StringBuilder : " + builderMillis + " ms");
}
}
Same result: true, length 238890 String += : 710 ms StringBuilder : 11 ms
StringBuilder was many times faster. The gap grows quickly as n grows, because += copies the ever-longer string on every pass.
StringBuilder, and is used in exactly the same way. The difference is that its methods are synchronized - only one thread at a time can run them on a given object - which makes a single StringBuffer safe to share between threads, at the cost of some speed.StringBuffer is the older class, part of Java since version 1.0. StringBuilder was added in Java 5 as a faster replacement for the common case where only one thread builds the string. In practice, strings are almost always built by one thread, so use StringBuilder. You will still see StringBuffer in older code and some older APIs.
StringBuffer has the same API
//BufferDemo.java
public class BufferDemo {
public static void main(String[] args) {
StringBuffer buffer = new StringBuffer("Java");
buffer.append(" 8").insert(0, "Learn ").append(" and beyond");
System.out.println(buffer);
System.out.println("Capacity: " + buffer.capacity() + ", length: " + buffer.length());
}
}
Learn Java 8 and beyond Capacity: 42, length: 23
new StringBuilder(expectedLength) creates a buffer of that size up front and avoids regrowing it.
String vs StringBuilder vs StringBuffer - comparison
| String | StringBuilder | StringBuffer | |
| Mutable? | No - immutable | Yes | Yes |
| Thread-safe? | Yes (because immutable) | No | Yes (synchronized methods) |
| Speed for many changes | Slow - new object each time | Fastest | Fast, slightly slower than StringBuilder |
| Since | Java 1.0 | Java 5 | Java 1.0 |
| equals() compares content? | Yes | No | No |
| Use for | Fixed text, map keys, values passed around | Building or editing text, especially in loops | Building text shared between threads (rare); older code |
Rule of thumb: use
String for values, + for joining in a single expression, and StringBuilder whenever you build text in a loop or in many steps.
Summary
In this tutorial we first saw why joining strings with += in a loop is slow - each pass copies the whole string into a new object. We then used StringBuilder, a mutable string, and its methods append(), insert(), replace(), delete(), reverse() and setLength(). Next we measured how much faster StringBuilder is. We then saw that StringBuffer is the older, synchronized version with the same methods. Lastly, we compared all three classes. In the next tutorial, we will write multi-line strings with text blocksClick to read tutorial: Java Text Blocks: Multi-line Strings with Examples.Java Fundamentals Tutorials
Essential Java String Methods with ExamplesClick to read tutorial: Essential Java String Methods with Examples Java Text Blocks: Multi-line Strings with ExamplesClick to read tutorial: Java Text Blocks: Multi-line Strings with Examples Java String Basics and Why Strings Are ImmutableClick to read tutorial: Java String Basics and Why Strings Are Immutable Java String Pool: String Literals vs new String()Click to read tutorial: Java String Pool: String Literals vs new String() Java String Comparison: == vs equals() vs compareTo()Click to read tutorial: Java String Comparison: == vs equals() vs compareTo() Common Java String Programs with ExamplesClick to read tutorial: Common Java String Programs with Examples What is Java? History, Features, Editions and UsesClick to read tutorial: What is Java? History, Features, Editions and Uses
Essential Java String Methods with ExamplesClick to read tutorial: Essential Java String Methods with Examples Java Text Blocks: Multi-line Strings with ExamplesClick to read tutorial: Java Text Blocks: Multi-line Strings with Examples Java String Basics and Why Strings Are ImmutableClick to read tutorial: Java String Basics and Why Strings Are Immutable Java String Pool: String Literals vs new String()Click to read tutorial: Java String Pool: String Literals vs new String() Java String Comparison: == vs equals() vs compareTo()Click to read tutorial: Java String Comparison: == vs equals() vs compareTo() Common Java String Programs with ExamplesClick to read tutorial: Common Java String Programs with Examples What is Java? History, Features, Editions and UsesClick to read tutorial: What is Java? History, Features, Editions and Uses