Fun with maps and sets
by Patrick Connelly posted on January 26, 2015
While working on Apex, I discovered an interesting behavior with Maps and the keySet method.
Problem
class TestData {
public String data;
public TestData() {}
public TestData(String data) {
this.data = data;
}
}
Map<String, TestData> dataMap = new Map<String, TestData>{
'foo' => new TestData('foo'),
'bar' => new TestData('bar')
};
Set<String> keySet = dataMap.keySet();
System.debug(keySet.size()); // 2
System.debug(dataMap.size()); // 2
keySet.remove('foo');
System.debug(keySet.size()); // 1
System.debug(dataMap.size()); // 1
This code does not behave how you would think. If you remove an item from the keySet set it also removes it from the dataMap. What I believe to be happening here is that the keySet method is returning a reference to the key set of the dataMap.
Solution
To work around this, we simply clone the keySet. This will give us a new instance of the set instead of the reference version.
class TestData {
public String data;
public TestData() {}
public TestData(String data) {
this.data = data;
}
}
Map<String, TestData> dataMap = new Map<String, TestData>{
'foo' => new TestData('foo'),
'bar' => new TestData('bar')
};
Set<String> keySet = dataMap.keySet().clone();
System.debug(keySet.size()); // 2
System.debug(dataMap.size()); // 2
keySet.remove('foo');
System.debug(keySet.size()); // 1
System.debug(dataMap.size()); // 2