8

I have created one class name like Test and have overriden its equals() and hashcode() methods and then created its 2 objects like below -

Test obj1 = new Test ();
Test obj2 = new Test ();

and now performaing following operation -

obj1.equals(obj2); // I am getting **True** that is fine.

But if i change i code bit like below -

Set<Test> testSet = new Set<Test>();
testSet.add(obj1);

Print : testSet.contains(obj2); // It is returning **False**....

I debug the code and found in this case HashCode() method is getting called but equals() is not being called. HashCode is some for both the object.

As per my understanding it should return True.

Modified --

My code is below -

Class

     public Class DMAClipLevelWrapperForExport {
        public String businessUnit {get; set;}
        public String dmaType {get; set;}
        public Decimal tcvMin {get; set;}
        public Decimal tcvMax {get; set;}        

        /*
         * Overriding equals
         */     
        public Boolean equals(DMAClipLevelWrapperForExport obj) { 
            if(obj != null){
                if(obj.tcvMin == this.tcvMin && obj.tcvMax == this.tcvMax) {
                    return true;
                } else {
                    return false;
                }
            } else {
                return false;
            }           
        }

        /*
         * Overriding hashCode
         */ 
        public Integer hashCode() {
            return this.tcvMin.intValue() + this.tcvMax.intValue();
        }
     }

Code written to test

        Set<DMAClipLevelWrapperForExport> dmaClipLevelWrapperForExport = new Set<DMAClipLevelWrapperForExport>();

        DMAClipLevelWrapperForExport one = new DMAClipLevelWrapperForExport();
        one.businessUnit = 'APACC';
        one.dmaType = 'CES';
    one.tcvMin = 0;
        one.tcvMax = 500000;
    dmaClipLevelWrapperForExport.add(one);

        DMAClipLevelWrapperForExport clipLevel = new DMAClipLevelWrapperForExport();
        clipLevel.businessUnit = 'APACC';
        clipLevel.dmaType = 'CES';
        clipLevel.tcvMin = 0;
        clipLevel.tcvMax = 500000;


    if(dmaClipLevelWrapperForExport.contains(clipLevel)) {
            system.assert(false, 'Object found in list');
        } else {
            system.assert(false, 'Object not found in list');
        }

Always getting 'Object not found in list'.

Can anyone explain what is wrong in this code please?

Thanks for reply

2
  • Please add some System.debug in the hashCode() and run the test so you can see what the hash for the object should be (also, personal preference, don't call the set with the name of the object;)). Finally, the last sentence "if.." makes little sense, it should be just "System.assert(true, dmaSet.contains(clipLevel));" and the test should pass. (plus, your hashCode returns Integer, while you sum to Numbers.. make it coherent or ad some casting, but you'll see this with the suggested debug eventually)
    – T. Rossi
    Commented Jul 7, 2014 at 16:08
  • @T.Rossi I have done all these test. I have checked that hashcode is same for both the object. What i have figured out is hashcode is same for both the object but still equals() is not getting called in case of contains() but Equals and hashcode both are getting called in case of equals(). Commented Jul 8, 2014 at 4:23

2 Answers 2

7
+50

The issue is that you have not used the correct method signature for overriding equals.

Your method signature is:

public Boolean equals(DMAClipLevelWrapperForExport)

The correct one to use is covered in the Using Custom Types in Map Keys and Sets documentation.

Adding equals and hashCode Methods to Your Class

To ensure that map keys of your custom type are compared correctly and their uniqueness can be determined consistently, provide an implementation of the following two methods in your class:

The equals method with this signature:

public Boolean equals(Object obj) {
     // Your implementation
}

The hashCode method with this signature:

public Integer hashCode() {
    // Your implementation
}

Changing your equals method to following gives me the correct results using the test method that you provided.

public Boolean equals(object obj) 
{ 
    if(obj != null && obj instanceof DMAClipLevelWrapperForExport)
    { 
        DMAClipLevelWrapperForExport dma = (DMAClipLevelWrapperForExport)obj;

        if(dma.tcvMin == this.tcvMin && dma.tcvMax == this.tcvMax) 
        {
            return true;
        } 
        else 
        {
            return false;
        }
    } 
    else 
    {
        return false;
    }           
}
3
  • nice one:).. well formatted code op.
    – T. Rossi
    Commented Jul 8, 2014 at 11:07
  • My bad. I overloaded equals() rather than overriding. Commented Jul 9, 2014 at 8:00
  • @PramodKumar Yeah, it's a really easy mistake to make. At least you have an answer now though! Commented Jul 9, 2014 at 8:26
6

It appears you may have a typo in your code; you are making a Set<Test> instead of a Set<Text>, which is somehow working in this case (probably because you have a class named Test that is for some reason compatible with Text).

I made an example class that shows why it's important to make sure you're using hashcode and equals correctly, showing how you can create absurd results:

public class Example {
    virtual class Generic {
        virtual integer hashCode() {
            return 0;
        }
        virtual boolean equals(object o) {
            return true;
        }
    }

    class Singleton extends Generic {
    }

    class Multiton extends Generic {
        override integer hashCode() {
            return Crypto.getRandomInteger();
        }
        override boolean equals(object o) {
            return false;
        }
    }

    public static void doExample() {
        Set<Generic> single = new Set<Generic>(), single2 = new Set<Generic>(), multi = new Set<Generic>();
        Singleton a = new Singleton(), b = new Singleton();
        Multiton c = new Multiton();

        single.add(a);
        single.add(b);

        single2.add(a);

        multi.add(c);
        multi.add(c);

        System.assertEquals(1, single.size());
        System.assertEquals(true, single.contains(a));
        System.assertEquals(true, single.contains(b));
        System.assertEquals(true, single.contains(new Singleton()));
        System.assertEquals(false, single.contains(c));
        System.assertEquals(2, multi.size());
        System.assertEquals(false, multi.contains(c));
        System.assertEquals(1, single2.size());
        System.assertEquals(true, single2.contains(a));
        System.assertEquals(true, single2.contains(b));
    }
}

Note here how I add two singletons to a set, yet the size remains 1, and any singleton I pass in matches any other existing singleton. Not that this isn't actually a singleton, since we are able to create multiple objects, but this shows how a set of misbehaving functions can return odd results.

Next, I add the same Multiton to the set twice, and it results in a size of 2 in the set, and yet contains returns false when I ask the set to confirm if c is present. There's a minuscule chance this code will fail, less than that of being struck by lightning or winning the lottery.

The Singleton class demonstrates that your code should indeed return true if written correctly. I only provided the opposite example to show how the same object could not appear in a set.

5
  • Yes that was typo. I have corrected that. I have pasted my code and test code as well. I tried to find out what i am doing wrong but couldn't find anything.. Can you please have a glance on code and provide your valuable comments? Commented Jul 3, 2014 at 12:06
  • In the second and third assert you are adding again a and b therefore your code is returning True. Reference are same in your code. my scenario is little bit different than your Commented Jul 3, 2014 at 12:20
  • @PramodKumar I provided a third example in the code that proves that it works the way it's documented.
    – sfdcfox
    Commented Jul 3, 2014 at 15:40
  • Yes i can see. But i am not able to figure out what is wrong in my code. I have written these kind of code in java many time but in salesforce i am not getting expected results. Commented Jul 4, 2014 at 4:34
  • @PramodKumar Perhaps you could post a gist or something? Sometimes the only way to see what's wrong is to see the actual code.
    – sfdcfox
    Commented Jul 4, 2014 at 5:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .