I was looking at the Java reflection classes and noticed this piece of code. Made me wonder, why Java uses StringBuffer when StringBuilder is faster?
Wouldn't Java want to use the fastest implementation, or is there some other reason?
The code is in the Field.class:
static String getTypeName(Class<?> type) {
if (type.isArray()) {
try {
Class<?> cl = type;
int dimensions = 0;
while (cl.isArray()) {
dimensions++;
cl = cl.getComponentType();
}
StringBuffer sb = new StringBuffer();
sb.append(cl.getName());
for (int i = 0; i < dimensions; i++) {
sb.append("[]");
}
return sb.toString();
} catch (Throwable e) { /*FALLTHRU*/ }
}
return type.getName();
}
The main reason is that the JVM has advanced techniques to see if can avoid having to do all sorts of things are they are implied by the context. Since the StringBuffer is a local variable that never escapes the method the JVM can safely avoid having to try and acquire a lock on the object before entering the StringBuffer's synchronised methods -- since no other thread will ever be able to call the methods of this particular instance of StringBuffer.
A quick micro benchmark bears this out. Making buffer
a field will slow down the following code by 50%.
private void doTest(String toCopy) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < toCopy.length(); i++) {
buffer.append(toCopy.charAt(i));
}
buffer.toString();
}
With a million length string and 1000 repetitions the above code runs in 8 seconds on my machine. However, once buffer
is made into a field rather than a local variable then it takes about 13 seconds (Since the JVM can no longer easily guarantee that buffer
will only be accessed by one thread).