In this example, StringBuffer is actually faster than StringBuilder, whereas I would have expected opposite results.
Is this something to do with optimizations being made by the JIT ? Does anyone know why StringBuffer would be faster than StringBuilder, even though it's methods are synchronized ?
Here's the code and the benchmark results:
public class StringOps {
public static void main(String args[]) {
long sConcatStart = System.nanoTime();
String s = "";
for(int i=0; i<1000; i++) {
s += String.valueOf(i);
}
long sConcatEnd = System.nanoTime();
long sBuffStart = System.nanoTime();
StringBuffer buff = new StringBuffer();
for(int i=0; i<1000; i++) {
buff.append(i);
}
long sBuffEnd = System.nanoTime();
long sBuilderStart = System.nanoTime();
StringBuilder builder = new StringBuilder();
for(int i=0; i<1000; i++) {
builder.append(i);
}
long sBuilderEnd = System.nanoTime();
System.out.println("Using + operator : " + (sConcatEnd-sConcatStart) + "ns");
System.out.println("Using StringBuffer : " + (sBuffEnd-sBuffStart) + "ns");
System.out.println("Using StringBuilder : " + (sBuilderEnd-sBuilderStart) + "ns");
System.out.println("Diff '+'/Buff = " + (double)(sConcatEnd-sConcatStart)/(sBuffEnd-sBuffStart));
System.out.println("Diff Buff/Builder = " + (double)(sBuffEnd-sBuffStart)/(sBuilderEnd-sBuilderStart));
}
}
Benchmark results:
Using + operator : 17199609ns
Using StringBuffer : 244054ns
Using StringBuilder : 4351242ns
Diff '+'/Buff = 70.47460398108615
Diff Buff/Builder = 0.056088353624091696
UPDATE:
Thanks to everyone. Warmup was indeed the problem. Once some warmup code was added, the benchmarks changed to:
Using + operator : 8782460ns
Using StringBuffer : 343375ns
Using StringBuilder : 211171ns
Diff '+'/Buff = 25.576876592646524
Diff Buff/Builder = 1.6260518726529685
YMMV, but at least the overall ratios agree with what would be expected.
I had a look at your code, and the most likely reason that StringBuilder
it appears to be slower is that your benchmark is not properly taking account of the effects of JVM warmup. In this case:
Either or both of these could add to the time measured for the StringBuilder
part of your test.
Please read the answers to this Question for more details: How do I write a correct micro-benchmark in Java?