Apex Oddities

Apex is, for the most part, a simplified version of Java. However, it has a few quirks and undocumented "features", which this article seeks to explore.

Maps use case-sensitive keys… mostly

Generally, Map keys in Apex are case-sensitive. However, there are a few exceptions to this rule! The global describe maps and subsequent field maps are case-insensitive:

// This one:
Map<String, Schema.SObjectType> gd = Schema.getGlobalDescribe();

// And this one:
Map<String, Schema.SObjectField> fieldMap =
gd.get(sObjectName).getDescribe().fields.getMap();

Cloned SObjects do not respect Decimal precision

Deep-cloning a List trims trailing zeroes from Decimal values therein.

List<MyObject__c> myList = new List<MyObject__c> {
  new MyObject(Decimal_Field__c = 1000.0000000)
};

List<MyObject__c> clonedList = myList.deepClone(true, true, true);

System.debug(myList.Decimal_Field__c); // 1000.0000000
System.debug(clonedList.Decimal_Field__c); // 1000.00
System.debug(myList == clonedList); // false (see related issue, below)

Equivalent Decimals are not always considered equal

Two equivalent Decimals with different levels of precision are considered equal. However, two Lists or SObjects containing such decimals are not!

Decimal a = 1000.00;
Decimal b = 1000.0000000;

System.debug(a == b); // true

List<Decimal> listA = new List<Decimal>{a};
List<Decimal> listB = new List<Decimal>{b};

System.debug(listA == listB); // false

MyObject__c objA = new MyObject__c(Decimal_Field__c = a);
MyObject__c objB = new MyObject__c(Decimal_Field__c = b);

System.debug(objA == objB); // false

This can be worked around by creating custom areListsEqual and areSObjectsEqual methods, which explicitly check for equality between each pair of items or fields, respectively.

Sets cannot be cast

Lists and Sets behave very differently where generics are concerned. More details can be found in this StackOverflow answer.

// This works fine:
List<MyObject__c> myList;
List<SObject> myUpcastList = (List<SObject>) myList;

// This can't be done!
Set<MyObject__c> mySet;
Set<SObject> myUpcastSet = (Set<SObject>) mySet;

Whitespace DOES matter

Unlike in Java, whitespace can sometimes cause compilation errors.

String body;

// Works
body = new System.HttpRequest()
        .getBody();

// Does not work
body = new System
        .HttpRequest()
        .getBody();

It seems like the inner class name cannot be separated from the containing class; System.HttpRequest is treated as a single token.

Thanks for reading!

And may you never stumble upon an Apex oddity of your own.

Published 20/11/2019

Last updated 09/03/2021