First, we have to remember that String is immutable and final in Java. Every modification of String (concatenation, substring, converting into lowercase or uppercase) creates a new String object. StringBuffer and StringBuilder are classes which allow us to manipulate String without creating garbage.
Append method implementations
What is the difference between them? Let’s look at the implementations of the method append(int)
from StringBuffer and StringBuilder.
StringBuffer:
1 2 3 4 5 6 7 |
public synchronized StringBuffer append(int i) { toStringCache = null; super.append(i); return this; } |
StringBuilder:
1 2 3 4 5 6 |
public StringBuilder append(int i) { super.append(i); return this; } |
Because each method of StringBuffer is synchronized, it is thread-safe. However, because of that, it’s also slower. StringBuilder provides an API compatible with StringBuffer, but it is more efficient, as it has no synchronized methods.
Performance test
Let’s do a performance test of those two classes. The code below measures the time of 108 appends of a single char ‘a’.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
StringBuffer stringBuffer = new StringBuffer(); StringBuilder stringBuilder = new StringBuilder(); long bufferTimeStart = System.currentTimeMillis(); for (long i = 0; i < Math.pow(10, 8); i++) { stringBuffer.append('a'); } long bufferTimeEnd = System.currentTimeMillis(); long builderTimeStart = System.currentTimeMillis(); for (long i = 0; i < Math.pow(10, 8); i++) { stringBuilder.append('a'); } long builderTimeEnd = System.currentTimeMillis(); System.out.println("StringBuffer: " + (bufferTimeEnd - bufferTimeStart) + " ms"); System.out.println("StringBuilder: " + (builderTimeEnd - builderTimeStart) + " ms"); |
Result:
1 2 3 4 |
StringBuffer: 3126 ms StringBuilder: 526 ms |
The result shows that execution time of StringBuilder’s methods is almost six times faster than StringBuffer’s methods. That is the reason why we should use StringBuilder rather than StringBuffer.