Being able to write your own equals/hashCode for a custom class seems appealing - see Non-primitive Types in Map Keys and Sets. But with no hashCode method exposed in Apex string or decimal or any of the other primitive types, building a correct and efficient hashCode for a custom class that has a few fields of different types looks way harder than it should be.
Suggestions?
Attribution to: Keith C
Possible Suggestion/Solution #1
Summer'13 Update:
According to the Summer'13 release notes String now provides a hashCode method! Here is the sample code included in the release notes here.
public class MyCustomClass {
String x,y;
public MyCustomClass(String a, String b) {
x=a;
y=b;
}
public Integer hashCode() {
return (31 * x.hashCode()) ^ y.hashCode();
}
public Boolean equals(Object obj) {
if (obj instanceof MyCustomClass) {
MyCustomClass p = (MyCustomClass)obj;
return (x.equals(p.x)) && (y.equals(p.y));
}
return false;
}
}
Original Answer:
Converted comment to an answer after a bit of digging around.
Initial thoughts...
Yes most interesting, I did wonder why the only sample was using numbers. It also looks like there is a bug in this area at large anyway, http://success.salesforce.com/issues_view?id=a1p30000000SV0XAAW.
Current conclusion...
I had a look at the Java implementations and a few other general postings on the net. My conclusion is that given the statement governor, at least for strings, it is going to quite expensive to implement a String.hashCode. We really need a native implementation of this to avoid hitting the statement governor very quickly with large maps.
Some interesting links
- http://java-bytes.blogspot.co.uk/2009/10/hashcode-of-string-in-java.html
- http://www.tgerm.com/2011/07/xcollections-using-udt-with-map-set-in.html
- http://en.wikipedia.org/wiki/Java_hashCode()
- http://www.javapractices.com/topic/TopicAction.do?Id=28
- https://stackoverflow.com/questions/113511/hash-code-implementation
Attribution to: Andrew Fawcett
Possible Suggestion/Solution #2
I realize Summer '13 is just around the corner, but if you are still looking for a way to create a hashcode out of strings (or any other object) without hitting governor limits, here is a method I pieced together using the solution found here
private static final Long prime = 524287L;
public static Integer getHashCode(Object obj) {
String objHex = null;
if(obj instanceof Id) {
objHex = EncodingUtil.convertToHex(Blob.valueOf((String)obj));
} else if(obj != null) {
Blob objJSONBlob = Blob.valueOf(JSON.serialize(obj));
Blob objHMAC = Crypto.generateMac('hmacSHA1', objJSONBlob, Blob.valueOf('a key that does not matter'));
objHex = EncodingUtil.convertToHex(objHMAC);
}
if(objHex != null) {
Long hash = 0L;
for(String sChar : objHex.split('')){
if(String.isEmpty(sChar)) {
continue;
}
hash = ((hash ^ hexToInteger.get(sChar)) * prime);
}
return (Integer)hash;
} else {
return 0;
}
}
Attribution to: Daniel Blackhall
This content is remixed from stackoverflow or stackexchange. Please visit https://salesforce.stackexchange.com/questions/4569