Find your content:

Search form

You are here

How to implement hashCode cleanly?

 
Share

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


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

My Block Status

My Block Content