Apex Null Handling and Errors
Null Handling and Safe Navigation
Safe Navigation Operator (?.)
The safe navigation operator (?.) returns null if the left operand is null, otherwise it evaluates the right operand. This prevents NullPointerException.
Usage Guidelines:
- Use safe navigation for chaining: When accessing properties or methods on potentially null objects
- Use explicit null checks for validation: When you need to validate input or handle null as an error condition
Examples:
// Good: Safe navigation for chaining
String objectName = record?.getSObjectType()?.getDescribe()?.getName();
List<SObject> results = queryResult?.getRecords();
// Good: Explicit check for validation
if (recordId == null) {
throw new ACME_ValidationException('Record ID is required');
}
// Good: Context-dependent usage
if (String.isNotBlank(querySort?.field)) {
// Process field
}
Null Coalescing Patterns
Use the null-coalescing operator (??) as the default fallback pattern for nullable values. Use ternary expressions when you need more complex branching logic.
Example:
// Preferred: Null-coalescing operator
String status = account.Status ?? 'Active';
Integer count = recordCount ?? 0;
// Use ternary when conditions are more complex than null fallback
String displayStatus = account.Status != null && account.Status != '' ? account.Status : 'Active';
Collection Initialization
Always initialize empty collections in constructors to avoid null pointer exceptions.
Example:
public class ACME_Response {
public List<SObject> results { get; set; }
public List<String> messages { get; set; }
public ACME_Response() {
results = new List<SObject>();
messages = new List<String>();
}
}
Error Handling
Exception Naming Conventions
- Use PascalCase with "Exception" suffix
- Be descriptive about the exception type
- Examples:
ValidationException,SecurityException,DataAccessException
Custom Exception Classes
Use custom exceptions for domain-specific failures where callers need a clear, actionable error type. Standard exceptions are acceptable for platform/system failures.
Current patterns in the codebase include:
TypeException- For type validation errorsFieldException- For field-related errorsPermissionException- For permission-related errorsValidationException- For general validation errors
Example:
public class ACME_ValidationException extends Exception { }
public static void validateRecord(Account acc) {
if (acc.Name == null) {
throw new ACME_ValidationException('Account name is required');
}
}
SOQL Result Handling
Always check isEmpty() before accessing query results to prevent index out of bounds exceptions.
Example:
List<Account> accounts = [SELECT Id, Name FROM Account LIMIT 10];
if (!accounts.isEmpty()) {
Account firstAccount = accounts[0];
// Process account
} else {
// Handle empty result
}
Try-Catch Patterns
- Always handle exceptions appropriately
- Never use empty catch blocks (violates Code Analyzer rules)
- Log errors appropriately (see Logging and Debugging)
- Return appropriate error responses for frontend methods
Example:
public static ACME_Response processRecord(Id recordId) {
ACME_Response response = new ACME_Response();
try {
Account acc = [SELECT Id, Name FROM Account WHERE Id = :recordId];
// Process account
response.results.add(acc);
} catch (QueryException e) {
System.debug('Error querying record: ' + e.getMessage());
response.success = false;
response.messages.add('Record not found');
} catch (Exception e) {
System.debug('Unexpected error: ' + e.getMessage());
response.success = false;
response.messages.add('An error occurred processing the record');
}
return response;
}
Error Message Best Practices
- Use clear, user-friendly error messages
- Include context when helpful (field name, record ID, etc.)
- Avoid exposing sensitive information
- Log detailed error information for debugging
Example:
throw new ACME_ValidationException('Account name is required');
throw new ACME_SecurityException('User does not have permission to access this record');
Change History
Version 1.0 - 2026-03-26
- Added initial version history tracking for this document.
Last Updated: 2026-03-26 Version: 1.0