Reputation: 4569
I stumbled upon a bizarre performance issue related to the StringBuilder
's append
method. I noticed what appeared to be a foolish mistake - string concatenation during the use of the StringBuilder
constructor (this even shows up as a warning in the NetBeans IDE).
Version 1
int hash = -1; //lazily computed, also present in Version 2
int blockID = ... //0 to 1000, also present in Version 2
int threadID = ... //0 to 1000, also present in Version 2
boolean hashed = false; //also present in Version 2
@Override
public int hashCode(){
if(!hashed){
StringBuilder s = new StringBuilder(blockID+":"+threadID);
hash = s.toString().hashCode();
hashed= true;
}
return hash;
}
Millions of these objects are created during runtime, so I thought by making the following change, it would provide some speedup:
Version 2
@Override
public int hashCode(){
if(!hashed){
StringBuilder s = new StringBuilder(blockID);
s.append(":");
s.append(threadID);
hash = s.toString().hashCode();
hashed = true;
}
return hash;
}
WRONG! Turns out, Version 2 is literally 100X slower than Version 1. Why???
Additional Info
I am compiling against Java 6 (customer requirement), and I am using Oracle's JVM.
My performance test involves creating a million of these objects and throwing them into a HashMap. It takes half a second to do it using Version 1, but almost 50 seconds to do it using Version 2.
Upvotes: 4
Views: 205
Reputation: 5569
Because you're inadvertently setting the initial capacity of the StringBuilder
instead of appending blockID
to it. See constructor documentation here.
public StringBuilder(int capacity)
Constructs a string builder with no characters in it and an initial capacity specified by the capacity argument.
Try this instead:
StringBuilder s = new StringBuilder(9);
s.append(blockID).append(':').append(threadID);
Upvotes: 14
Reputation: 533492
You need to check your test as your first case is actually doing.
public int hashCode(){
if(!hashed){
StringBuilder s = new StringBuilder(
new StringBuilder(blockID).append(":").append(threadID).toString());
hash = s.toString().hashCode();
hashed= true;
}
return hash;
}
In other words it is doing everything in the second case and more so it will be slower.
In short, I suspect your test is wrong, not that you are getting better performance.
Upvotes: 1