Using Custom Types in Map Keys and Sets

You can add instances of your own Apex classes to maps and sets.

For maps, instances of your Apex classes can be added either as keys or values, but if you add them as keys, there are some special rules that your class must implement for the map to function correctly, that is, for the key to fetch the right value. Similarly, if set elements are instances of your custom class, your class must follow those same rules.

Warning

Warning

If the object in your map keys or set elements changes after being added to the collection, it won’t be found anymore because of changed field values.

When using a custom type (your Apex class) for the map key or set elements, provide equals and hashCode methods in your class. Apex uses these two methods to determine equality and uniqueness of keys for your objects.

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
    }
    
    Keep in mind the following when implementing the equals method. Assuming x, y, and z are non-null instances of your class, the equals method must be:
    • Reflexive: x.equals(x)
    • Symmetric: x.equals(y) should return true if and only if y.equals(x) returns true
    • Transitive: if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true
    • Consistent: multiple invocations of x.equals(y) consistently return true or consistently return false
    • For any non-null reference value x, x.equals(null) should return false

    The equals method in Apex is based on the equals method in Java.

  • The hashCode method with this signature:
    public Integer hashCode() {
        // Your implementation
    }
    Keep in mind the following when implementing the hashCode method.
    • If the hashCode method is invoked on the same object more than once during execution of an Apex request, it must return the same value.
    • If two objects are equal, based on the equals method, hashCode must return the same value.
    • If two objects are unequal, based on the result of the equals method, it is not required that hashCode return distinct values.

    The hashCode method in Apex is based on the hashCode method in Java.

Another benefit of providing the equals method in your class is that it simplifies comparing your objects. You will be able to use the == operator to compare objects, or the equals method. For example:
// obj1 and obj2 are instances of MyClass
if (obj1 == obj2) {
    // Do something
}

if (obj1.equals(obj2)) {
    // Do something
}

Sample

This sample shows how to implement the equals and hashCode methods. The class that provides those methods is listed first. It also contains a constructor that takes two Integers. The second example is a code snippet that creates three objects of the class, two of which have the same values. Next, map entries are added using the pair objects as keys. The sample verifies that the map has only two entries since the entry that was added last has the same key as the first entry, and hence, overwrote it. The sample then uses the == operator, which works as expected because the class implements equals. Also, some additional map operations are performed, like checking whether the map contains certain keys, and writing all keys and values to the debug log. Finally, the sample creates a set and adds the same objects to it. It verifies that the set size is two, since only two objects out of the three are unique.

public class PairNumbers {
    Integer x,y;

    public PairNumbers(Integer a, Integer b) {
        x=a;
        y=b;
    }

    public Boolean equals(Object obj) {
        if (obj instanceof PairNumbers) {
            PairNumbers p = (PairNumbers)obj;
            return ((x==p.x) && (y==p.y));
        }
        return false;
    }

    public Integer hashCode() {
        return (31 * x) ^ y;
    }
}

This code snippet makes use of the PairNumbers class.

Map<PairNumbers, String> m = new Map<PairNumbers, String>();
PairNumbers p1 = new PairNumbers(1,2);
PairNumbers p2 = new PairNumbers(3,4);
// Duplicate key
PairNumbers p3 = new PairNumbers(1,2);
m.put(p1, 'first');
m.put(p2, 'second');
m.put(p3, 'third');

// Map size is 2 because the entry with 
// the duplicate key overwrote the first entry.
System.assertEquals(2, m.size());

// Use the == operator
if (p1 == p3) {
    System.debug('p1 and p3 are equal.');
}

// Perform some other operations
System.assertEquals(true, m.containsKey(p1));
System.assertEquals(true, m.containsKey(p2));
System.assertEquals(false, m.containsKey(new PairNumbers(5,6)));

for(PairNumbers pn : m.keySet()) {
    System.debug('Key: ' + pn);
}

List<String> mValues = m.values();
System.debug('m.values: ' + mValues);

// Create a set
Set<PairNumbers> s1 = new Set<PairNumbers>();
s1.add(p1);
s1.add(p2);
s1.add(p3);

// Verify that we have only two elements
// since the p3 is equal to p1.
System.assertEquals(2, s1.size());
Previous
Next