In guava code (which I think one of examples of high quality code) I've found following fragment:
// If the cachedHashCode is 0, it will always be recalculated, unfortunately.
private transient int cachedHashCode;
public final int hashCode() {
// Racy single-check.
int code = cachedHashCode;
if (code == 0) {
cachedHashCode = code = element.hashCode();
}
return code;
}
So "If the cachedHashCode is 0, it will always be recalculated, unfortunately". Another example is JDK String.hashCode
:
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
It also tries to calculate hash code once, but fails if hashCode of String is 0 (example of such string is "\0"
).
Simple solution to avoid such recalculations would be addition of extra check on calculation:
if (hash == 0) hash++;
Although it very slightly slows the hashCode
calculation down in general case but this trick allows to avoid worst case scenario when it repeatedly (and slowly (for long string for example)) calculated again and again.
Why it isn't used in guava ImmutableSet
nor JDK String
?
Edit
Recent Java 7 releases added custom String.hash32
implementation which contains handling of this special case:
// ensure result is not zero to avoid recalcing
h = (0 != h) ? h : 1;