[SalesForce] Changing map key values

I'm confused about what happens when i change part of the key value of a map. For instance:

account a = new account(name = 'account name', website = 'www.testdomain.com');
map<account, string> someMap = new map <account, string>();
someMap.put(a, 'tra la li la');

Now let's change the website and see what happens.

a.website = 'www.salesforce.com';
system.debug('a: ' + a + '\n' + 'someMap: ' + someMap);
if(someMap.containsKey(a)){system.debug('key found' );}
else{system.debug('key isnt found');}

Debug result:
a: Account:{Name=acount name, Website=www.salesforce.com}
someMap: {Account:{Name=account name, Website=www.salesforce.com}=null}
Key isnt found

As i understand this, the account is passed by reference and therefore the website in the map has also changed. However, why does this change the string value to null? Also why doesn't the map contain the account key anymore, even though both the original account and the map key have both been changed in exactly the same way?

Now let's put in the same account once more:

someMap.put(a, 'tra la li la');
system.debug('a: ' + a);
system.debug'someMap: ' + someMap);
if(someMap.containsKey(a)){system.debug('key found' );}

Debug result:
a: Account:{Name=account name, Website=www.salesforce.com}
someMap: {Account:{Name=account name, Website=www.salesforce.com}=tra la li la}
key found

Before, i was told the key value doesn't exist, but now when i add the account again, it overwrites the original key instead of adding an extra value. Why does it do that?

I find this behavior confusing. I'd like to understand the logic behind it.

Best Answer

Have a read of articles such as this Wikipedia Hash table article to learn about how buckets are used to speed up retrieval from maps.

When the Account is first added to the map, its hashCode method returns a value that determines which bucket the key is allocated to. When you change one of the fields of the Account object, you change the value returned by the hashCode method and so very likely change the bucket that is looked in for the key value so it is no longer found, hence the null result.

Using an SObject as the map key is rarely a good choice because SObjects are often changed in code. (It's also potentially costly in CPU time as all the fields of the SObject have to be examined to generate the hash code and to check for equality.) If an SObject has an Id value defined use that as the key instead.

Related Topic