Apex Syntax, Data Types & Collections
š Concept
Apex is Salesforce's proprietary, strongly-typed, object-oriented programming language. It runs on the Salesforce servers (not client-side) and is specifically designed for the multi-tenant environment.
Key characteristics:
- Java-like syntax ā if you know Java, Apex feels familiar
- Strongly typed ā all variables must be declared with types
- Governor-limit-aware ā designed to run within strict resource constraints
- Database-integrated ā SOQL/SOSL and DML are first-class citizens
- Cloud-executed ā runs on Salesforce servers, not client machines
Primitive Data Types:
Integer ā 32-bit whole numbers
Long ā 64-bit whole numbers
Double ā 64-bit floating point
Decimal ā Arbitrary precision (for currency)
String ā Text (no character limit in Apex, but fields have limits)
Boolean ā true/false
Date ā Date without time
Datetime ā Date with time
Time ā Time without date
Id ā 18-character Salesforce record ID
Blob ā Binary data
Collections (the workhorses of Apex):
List ā Ordered collection (allows duplicates)
- Indexed by integer position (0-based)
- Most common collection for processing records
List<Account> accounts = new List<Account>();
Set ā Unordered collection of UNIQUE elements
- Automatically deduplicates
- Fast lookup (O(1) contains check)
Set<Id> accountIds = new Set<Id>();
Map ā Key-value pairs (unique keys)
- O(1) lookup by key
- The most powerful collection for bulkification
Map<Id, Account> accountMap = new Map<Id, Account>();- Can be initialized directly from SOQL:
new Map<Id, Account>([SELECT ...])
Why Maps are critical: In bulkified code, you constantly need to look up related data. Without Maps, you'd need nested loops (O(n²)). Maps give you O(1) lookups, keeping your code performant within governor limits.
SObject ā the universal data type:
All Salesforce records are SObjects. Account, Contact, CustomObject__c are all subtypes of SObject. You can use SObject generically for dynamic code.
š» Code Example
1// Apex Fundamentals ā Data Types & Collections23public class ApexFundamentals {45 // Primitive types6 public static void primitiveExamples() {7 Integer count = 42;8 Long bigNumber = 2147483648L;9 Double pi = 3.14159;10 Decimal price = 99.99; // Use Decimal for money!11 String name = 'Salesforce Developer';12 Boolean isActive = true;13 Date today = Date.today();14 Datetime now = Datetime.now();15 Id accountId = '001000000000001'; // 15 or 18 char1617 // String methods18 String upper = name.toUpperCase();19 Boolean hasForce = name.contains('force');20 String[] parts = name.split(' ');21 String formatted = String.format('Hello {0}, today is {1}',22 new List<Object>{name, today});23 }2425 // LIST ā Ordered, allows duplicates26 public static void listExamples() {27 // Declaration & initialization28 List<String> fruits = new List<String>{'Apple', 'Banana', 'Cherry'};2930 // Common operations31 fruits.add('Date'); // Add to end32 fruits.add(1, 'Avocado'); // Insert at index33 String first = fruits.get(0); // Access by index34 fruits.set(0, 'Apricot'); // Replace at index35 Integer size = fruits.size(); // Count36 Boolean has = fruits.contains('Banana'); // Check existence37 fruits.sort(); // Sort in place38 fruits.remove(0); // Remove by index3940 // List of SObjects (most common usage)41 List<Account> accounts = [SELECT Id, Name FROM Account LIMIT 10];4243 // Iterate44 for (Account acc : accounts) {45 System.debug(acc.Name);46 }4748 // List initialization from SOQL49 List<Contact> contacts = [50 SELECT Id, FirstName, LastName, Email51 FROM Contact52 WHERE AccountId IN :accountIds53 ];54 }5556 // SET ā Unordered, unique values only57 public static void setExamples() {58 Set<String> uniqueCities = new Set<String>();59 uniqueCities.add('San Francisco');60 uniqueCities.add('New York');61 uniqueCities.add('San Francisco'); // Ignored ā already exists!62 System.assertEquals(2, uniqueCities.size());6364 // Most common pattern: collecting IDs for bulk queries65 Set<Id> accountIds = new Set<Id>();66 for (Contact c : contacts) {67 if (c.AccountId != null) {68 accountIds.add(c.AccountId);69 }70 }7172 // Use Set in SOQL WHERE IN clause73 List<Account> relatedAccounts = [74 SELECT Id, Name FROM Account WHERE Id IN :accountIds75 ];7677 // Set operations78 Set<String> setA = new Set<String>{'A', 'B', 'C'};79 Set<String> setB = new Set<String>{'B', 'C', 'D'};80 setA.retainAll(setB); // Intersection: {'B', 'C'}81 // setA.addAll(setB); // Union82 // setA.removeAll(setB); // Difference83 }8485 // MAP ā Key-value pairs (THE critical collection)86 public static void mapExamples() {87 // Basic Map88 Map<String, Integer> wordCount = new Map<String, Integer>();89 wordCount.put('apex', 5);90 wordCount.put('soql', 3);91 Integer count = wordCount.get('apex'); // 592 Boolean hasKey = wordCount.containsKey('soql'); // true93 Set<String> allKeys = wordCount.keySet();94 List<Integer> allValues = wordCount.values();9596 // ā THE MOST IMPORTANT PATTERN: Map from SOQL97 // Initialize Map<Id, SObject> directly from query98 Map<Id, Account> accountMap = new Map<Id, Account>(99 [SELECT Id, Name, Industry FROM Account WHERE Industry = 'Technology']100 );101102 // Now O(1) lookup by ID!103 Account acc = accountMap.get(someAccountId);104105 // Map for parent lookup in triggers106 Map<Id, Account> parentAccounts = new Map<Id, Account>(107 [SELECT Id, Name FROM Account WHERE Id IN :accountIds]108 );109110 for (Contact c : Trigger.new) {111 Account parentAcc = parentAccounts.get(c.AccountId);112 if (parentAcc != null) {113 // Use parent data without additional queries114 System.debug('Contact belongs to: ' + parentAcc.Name);115 }116 }117118 // Map with complex keys119 Map<String, List<Contact>> contactsByCity = new Map<String, List<Contact>>();120 for (Contact c : contacts) {121 String city = c.MailingCity;122 if (!contactsByCity.containsKey(city)) {123 contactsByCity.put(city, new List<Contact>());124 }125 contactsByCity.get(city).add(c);126 }127 }128129 // SObject ā generic record type130 public static void sObjectExamples() {131 // Generic SObject usage132 SObject record = new Account(Name = 'Test');133 record.put('Industry', 'Technology'); // Dynamic field access134 String name = (String) record.get('Name');135136 // Get the SObject type137 Schema.SObjectType objType = record.getSObjectType();138 System.debug(objType); // Account139140 // Cast to specific type141 if (record instanceof Account) {142 Account acc = (Account) record;143 System.debug(acc.Name);144 }145 }146}
šļø Practice Exercise
Apex Fundamentals Practice:
- Write a method that takes a List
and returns a Map<String, Integer> counting character frequency - Given a List of Contacts, build a Map<Id, List
> grouping contacts by AccountId - Write a method that deduplicates a List
while preserving order (use Set + List) - Create a method that merges two Map<String, Integer> objects, summing values for duplicate keys
- Write a utility that converts a List
to a Map<String, SObject> using any specified field as the key - Implement a simple stack (LIFO) using a List
- Write a method that finds the intersection of two List
collections - Build a frequency counter that returns the top N most common values from a List
- Write a method that takes generic SObject records and populates a specified field
- Create a batch-safe collection splitter that breaks a List into chunks of N items
ā ļø Common Mistakes
Using Double or Float for currency calculations ā always use Decimal to avoid floating-point precision errors
Not initializing collections before use ā 'List
accounts;' is null, not empty. Always use 'new List ()' Forgetting that Map.get() returns null for missing keys ā always check containsKey() or handle null returns
Using List.contains() for large lookups ā O(n) per call. Use a Set for O(1) lookups when checking membership
Not understanding that Apex Strings are compared case-sensitively by default ā use .equalsIgnoreCase() or .toLowerCase() for case-insensitive comparison
š¼ Interview Questions
š¤ Mock Interview
Mock interview is powered by AI for Apex Syntax, Data Types & Collections. Login to unlock this feature.