5

I have seen at least one other question where a user has had issues with using Decimals as map keys (his issue was interchangeably using ints vs decimals), but it isn't the same issue I'm having, where Decimal keys appear to be treated as Strings for comparison:

Map<Decimal,String> m = new Map<Decimal,String>();
m.put(3.10,'Decimal key with trailing zero');
List<Decimal> keys = new List<Decimal>(m.keySet());
Decimal d = keys.get(0);

//Both of these statements should be true. If not, at the very least,
//      they should both be false
System.debug(d+' = 3.1? '+(d == 3.1));//3.10 = 3.1? true
System.debug('CONTAINS KEY 3.1? '+m.containsKey(3.1));//CONTAINS KEY 3.1? false

//I can successfully add a Decimal key equivalent to one already in the Collection
m.put(3.1,'Equivalent Decimal key without trailing zero');
System.debug('SIZE = '+m.keySet().size());//SIZE = 2

//Again, the Decimal objects are equal
Decimal d1 = 3.1;
Decimal d2 = 3.10;
System.debug('Values are equal? '+(d1 == d2));//Values are equal? true

//But even if I remove the shorter value....
String removeValue = m.remove(3.1);
System.debug('removeValue = '+removeValue);//removeValue = Equivalent Decimal key without trailing zero

//...It will not match in the get statement either
String res = m.get(d1);
System.debug('Res == null? '+(res == null));//Res == null? true

Am I missing something?

2
  • It is the same issue though, if you change the scale of a decimal, you change its hashCode, even if its value stays the same.
    – Adrian Larson
    Commented Feb 5, 2016 at 17:41
  • Well that is definitely a bug. As generally one expect apex to follow the same contracts as Java. baeldung.com/java-equals-hashcode-contracts Meaning any two objects which are equal must also generate the same hashcode!
    – Bill
    Commented Mar 18, 2019 at 21:47

2 Answers 2

5

Check out Using Custom Types in Map Keys and Sets to get a better understanding of how the uniqueness properties of objects are determined.

Map keys use the hashCode and equals methods to determine if two map/set keys are the same. The values 3.1 and 3.10 are "equal". However, the system hashes them differently, so they end up being considered unique.

system.assertEquals(3.1, 3.10);
system.assertNotEquals(system.hashCode(3.1), system.hashCode(3.10));

You can see a more complete answer here.

1
  • Comments are not for extended discussion; this conversation has been moved to chat.
    – Adrian Larson
    Commented Mar 20, 2019 at 17:11
3

in the map, the keys are specific values. So having 2 decimals 3.10 and 3.1 with difference Scale are different Keys in the map. If you compare 3.10 and 3.1 as decimals they will return the same because salesforce does the scaling automatically for ease of use in most situations.

4
  • I don't understand. If Apex holds 2 Decimals to be equivalent regardless of scaling (as demonstrated above where d1==d2), then why are they suddenly not equal when used in Maps. If Salesforce is making unequal objects equal "for ease of use in most situations", isn't this a fundamental flaw?
    – sheriffJT
    Commented Feb 5, 2016 at 17:42
  • A further implication is that Sets can't be used to enforce uniqueness in a collection of Decimals, as it will store 3.1, 3.10, 3.100, etc.
    – sheriffJT
    Commented Feb 5, 2016 at 17:59
  • @sheriffJT It's the difference between equals and hashCode. It's true that (3.1).equals(3.10). But their hashCode values differ so they are considered unique. Maps are basically hash tables.
    – Adrian Larson
    Commented Feb 5, 2016 at 18:37
  • See Using Custom Types in Map Keys and Sets in the docs, but what you're describing is precisely correct. Two values are "equal" in a set only if equals and hashCode both agree that an object is identical. Unfortunately, Decimals only match if the precision and scale both match as far as hashCode is concerned. I'm pretty sure this is a bug, but that's what we have to deal with. Make sure the values are properly rounded/truncated to use Decimal in those cases.
    – sfdcfox
    Commented Feb 5, 2016 at 18:55

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