The focus of this question is how the Apex compiler/runtime behave with maps that include static initialization data. So assuming a map of fixed values needs to be setup purely in Apex...
The simplest way to code that is like this:
private static final Map<String, String> ISO_TO_SYMBOL = new Map<String, String>{
'USD' => '$',
'CAD' => '$',
'EUR' => '€',
'GBP' => '£',
'JPY' => '¥',
'KRW' => '₩',
'CNY' => '元',
...
};
A more convoluted way is:
private static Map<String, String> ISO_TO_SYMBOL {
get {
if (ISO_TO_SYMBOL == null) {
ISO_TO_SYMBOL = new Map<String, String>{
'USD' => '$',
'CAD' => '$',
'EUR' => '€',
'GBP' => '£',
'JPY' => '¥',
'KRW' => '₩',
'CNY' => '元',
...
};
}
}
return ISO_TO_SYMBOL;
}
set;
}
A reason to take the second approach would be if the map initialisation was done at run time rather than compile time so cost was incurred every time the class was loaded (and only some methods in the class used the data so those that didn't would bear a needless cost). Also consider that if many classes are loaded to process a request, there could be many such maps resulting in hundreds or thousands of map put
s being needlessly done.
Does anyone have an evidence-backed view on which pattern is best in Apex?
PS
It occurred to me to look at the (finest level) debug log for a test case:
@IsTest
private class MapTest {
private static final Map<String, String> M1 = new Map<String, String>{
'abc' => '123',
'def' => '456'
};
private static Map<String, String> M2 {
get {
if (M2 == null) M2 = new Map<String, String>{
'PQR' => '987',
'STU' => '654'
};
return M2;
}
set;
}
@IsTest
static void test() {
// Touches neither map
}
}
which yielded:
07:17:02.0 (434345)|CODE_UNIT_STARTED|[EXTERNAL]|01p46000006cDFz|MapTest.test
07:17:02.0 (652740)|VARIABLE_SCOPE_BEGIN|[4]|MapTest.M1|Map<String,String>|true|true
07:17:02.0 (813407)|VARIABLE_SCOPE_BEGIN|[9]|MapTest.M2|Map<String,String>|true|true
07:17:02.0 (978657)|HEAP_ALLOCATE|[72]|Bytes:3
07:17:02.0 (1039411)|HEAP_ALLOCATE|[77]|Bytes:152
07:17:02.0 (1059294)|HEAP_ALLOCATE|[342]|Bytes:408
07:17:02.0 (1079287)|HEAP_ALLOCATE|[355]|Bytes:408
07:17:02.0 (1096414)|HEAP_ALLOCATE|[467]|Bytes:48
07:17:02.0 (1126412)|HEAP_ALLOCATE|[139]|Bytes:6
07:17:02.0 (1142006)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:84
07:17:02.0 (1169464)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:1
07:17:02.0 (1184616)|METHOD_ENTRY|[2]|01p46000006cDFz|MapTest.MapTest()
07:17:02.0 (1189674)|STATEMENT_EXECUTE|[2]
07:17:02.0 (1195887)|STATEMENT_EXECUTE|[2]
07:17:02.0 (1197317)|STATEMENT_EXECUTE|[4]
07:17:02.0 (1204261)|HEAP_ALLOCATE|[4]|Bytes:4
07:17:02.0 (1216226)|HEAP_ALLOCATE|[5]|Bytes:3
07:17:02.0 (1219723)|HEAP_ALLOCATE|[5]|Bytes:3
07:17:02.0 (1278906)|HEAP_ALLOCATE|[6]|Bytes:3
07:17:02.0 (1283649)|HEAP_ALLOCATE|[6]|Bytes:3
07:17:02.0 (1334734)|VARIABLE_ASSIGNMENT|[4]|MapTest.M1|{"abc":"123","def":"456"}|0x4d6865da
07:17:02.0 (1345930)|METHOD_EXIT|[2]|MapTest
07:17:02.0 (1382667)|HEAP_ALLOCATE|[50]|Bytes:5
07:17:02.0 (1411089)|HEAP_ALLOCATE|[56]|Bytes:5
07:17:02.0 (1418801)|HEAP_ALLOCATE|[64]|Bytes:7
07:17:02.0 (1459133)|STATEMENT_EXECUTE|[21]
I interpret the VARIABLE_ASSIGNMENT in that to mean that a reference to an already created (at compile time) map is being assigned. Touching M2 in the test results in a similar VARIABLE_ASSIGNMENT. So I'm starting to conclude that the simplest coding is the way to go for static initialization data.