Exception Handling in Apex
Exception Handling in Apex is a critical mechanism for managing runtime errors gracefully in Salesforce development. Apex uses a try-catch-finally block structure, similar to Java, to handle exceptions and prevent unhandled errors from disrupting business processes. **Try-Catch-Finally Structure:*… Exception Handling in Apex is a critical mechanism for managing runtime errors gracefully in Salesforce development. Apex uses a try-catch-finally block structure, similar to Java, to handle exceptions and prevent unhandled errors from disrupting business processes. **Try-Catch-Finally Structure:** - **Try Block:** Contains the code that might throw an exception. - **Catch Block:** Catches and handles specific exception types. Multiple catch blocks can handle different exception types. - **Finally Block:** Executes regardless of whether an exception occurred, typically used for cleanup operations. **Common Exception Types:** - **DmlException:** Occurs during DML operations (insert, update, delete) such as validation rule failures or required field violations. - **QueryException:** Thrown when a SOQL query returns unexpected results, like assigning multiple rows to a single sObject. - **NullPointerException:** Triggered when referencing a null object. - **ListException:** Occurs when accessing an invalid list index. - **LimitException:** Thrown when governor limits are exceeded (cannot be caught). - **CustomException:** User-defined exceptions extending the base Exception class. **Key Methods on Exception Objects:** - `getMessage()` – Returns the error message. - `getCause()` – Returns the cause of the exception. - `getLineNumber()` – Returns the line number where the exception occurred. - `getStackTraceString()` – Returns the full stack trace. **Custom Exceptions:** Developers can create custom exception classes by extending the Exception class: `public class MyCustomException extends Exception {}` These can be thrown using: `throw new MyCustomException('Custom error message');` **Best Practices:** 1. Catch specific exceptions before generic ones. 2. Never use empty catch blocks—always log or handle errors appropriately. 3. Use Database methods (Database.insert) with allOrNone=false for partial processing instead of relying solely on try-catch for DML. 4. Remember that LimitException and some system exceptions cannot be caught. Proper exception handling ensures robust automation, improves debugging, and delivers meaningful error messages to users in triggers, batch classes, and other Apex contexts.
Exception Handling in Apex: A Complete Guide for Salesforce Platform Developer 1 Exam
Why Exception Handling in Apex Matters
Exception handling is a critical concept for any Salesforce developer and a key topic on the Platform Developer 1 exam. Without proper exception handling, your Apex code can fail unpredictably, resulting in poor user experiences, lost data, and difficult-to-debug issues. Understanding how to anticipate, catch, and gracefully manage errors is essential for writing robust, production-ready code. On the exam, you can expect multiple questions that test your knowledge of try-catch-finally blocks, exception types, custom exceptions, and best practices.
What Is Exception Handling in Apex?
An exception is an event that disrupts the normal flow of program execution. In Apex, exceptions are objects that represent errors. When an error occurs — such as dividing by zero, referencing a null object, or violating a DML constraint — the Apex runtime throws an exception. If the exception is not handled, the entire transaction is rolled back and the user sees an unhandled error message.
Exception handling is the mechanism by which developers anticipate potential errors and write code to deal with them gracefully, rather than allowing the application to crash.
How Exception Handling Works in Apex
1. The try-catch-finally Structure
The core syntax for handling exceptions in Apex uses three keywords:
• try – The block of code that might throw an exception is placed inside a try block.
• catch – One or more catch blocks follow the try block. Each catch block specifies the type of exception it handles and contains the logic to respond to that exception.
• finally – An optional block that executes regardless of whether an exception was thrown or not. This is typically used for cleanup operations.
Example structure:
try {
// Code that might throw an exception
Account acc = [SELECT Id FROM Account WHERE Name = 'Test' LIMIT 1];
} catch (QueryException e) {
// Handle a specific exception type
System.debug('Query failed: ' + e.getMessage());
} catch (Exception e) {
// Handle any other exception
System.debug('General error: ' + e.getMessage());
} finally {
// Code that always executes
System.debug('Execution completed.');
}
2. Common Built-In Exception Types
Salesforce provides many built-in exception classes. The most commonly tested ones include:
• DmlException – Thrown when a DML operation (insert, update, delete, upsert, undelete, merge) fails. For example, a required field is missing or a validation rule is violated.
• QueryException – Thrown when a SOQL query encounters a problem, such as assigning a query that returns no rows to a single sObject variable (as opposed to a list).
• NullPointerException – Thrown when you try to dereference a null variable (e.g., calling a method on a null object reference).
• ListException – Thrown when there is an issue with list operations, such as accessing an index that is out of bounds.
• MathException – Thrown for illegal math operations like dividing by zero.
• LimitException – Thrown when a governor limit is exceeded. Important: LimitException cannot be caught. This is a frequently tested point on the exam.
• TypeException – Thrown when there is an issue with type conversion.
• SObjectException – Thrown when attempting to access a field on an sObject that was not queried.
• JSONException – Thrown when there is an error parsing or serializing JSON.
• CalloutException – Thrown when there is a problem with an HTTP callout or web service call.
3. The Exception Class Hierarchy
All exceptions in Apex extend the base Exception class. This means you can catch any exception by catching Exception, but it is best practice to catch the most specific exception types first. If you place a catch block for Exception before more specific types, the specific catch blocks will never be reached.
Order matters: always place more specific catch blocks before the generic Exception catch block.
4. Key Methods on the Exception Class
Every exception object provides several useful methods:
• getMessage() – Returns the error message associated with the exception.
• getTypeName() – Returns the type of exception (e.g., 'System.DmlException').
• getCause() – Returns the exception that caused the current exception, if any.
• getLineNumber() – Returns the line number where the exception occurred.
• getStackTraceString() – Returns the full stack trace as a string.
For DmlException specifically, additional methods are available:
• getDmlFieldNames(index) – Returns the field names that caused the error for the specified failed row.
• getDmlMessage(index) – Returns the error message for the specified failed row.
• getDmlStatusCode(index) – Returns the status code for the specified failed row.
• getDmlIndex(index) – Returns the original row index of the failed row.
• getNumDml() – Returns the number of failed rows.
5. Creating Custom Exceptions
You can create your own exception classes by extending the Exception class. Custom exception class names must end with the word 'Exception'. This is enforced by the compiler.
Example:
public class MyCustomException extends Exception {}
You can then throw it like this:
throw new MyCustomException('Something went wrong in my custom logic.');
Custom exceptions can be caught just like built-in exceptions using try-catch blocks. You can also add custom properties and methods to your custom exception classes.
6. Throwing Exceptions
You can manually throw exceptions using the throw keyword. This is useful when you want to enforce business logic or signal an error condition.
Example:
if (accountList.isEmpty()) {
throw new MyCustomException('No accounts found for processing.');
}
When constructing exception objects, you can use several constructors:
• new MyCustomException() – No message
• new MyCustomException('message') – With a message
• new MyCustomException(causeException) – With a cause
• new MyCustomException('message', causeException) – With both a message and a cause
7. Database Methods and Exception Handling
This is a critical concept for the exam. Apex provides two approaches to DML:
• Standard DML statements (insert, update, delete, etc.) – These throw a DmlException if any record fails. The entire operation is atomic: if one record fails, all records in the operation fail.
• Database class methods (Database.insert, Database.update, etc.) – These accept an optional allOrNone parameter. When set to false, partial success is allowed. Records that succeed are committed, and records that fail are not. Instead of throwing an exception, these methods return Database.SaveResult[] (or similar result objects) that you can inspect to determine which records succeeded and which failed.
Example:
Database.SaveResult[] results = Database.insert(accountList, false);
for (Database.SaveResult sr : results) {
if (!sr.isSuccess()) {
for (Database.Error err : sr.getErrors()) {
System.debug('Error: ' + err.getMessage());
}
}
}
Key exam point: Database methods with allOrNone = false do not throw DmlExceptions for individual record failures. You must check the results manually.
8. Transaction Control and Savepoints
Apex supports savepoints, which work in conjunction with exception handling to allow partial rollbacks:
Savepoint sp = Database.setSavepoint();
try {
insert newAccount;
insert newContact;
} catch (DmlException e) {
Database.rollback(sp);
// Handle the error
}
When a rollback is performed, all DML operations that occurred after the savepoint are undone.
9. Unhandled Exceptions and Governor Limits
If an exception is thrown and not caught, the Apex runtime rolls back the entire transaction. All DML operations performed during that transaction are reversed. The user typically sees an error page or message.
Remember: LimitException (thrown when governor limits are exceeded) cannot be caught in a try-catch block. The transaction is automatically rolled back. This is one of the most commonly tested exception-handling facts on the exam.
10. Exceptions in Triggers
In triggers, you can use the addError() method on sObject records or fields to prevent DML operations from completing and display user-friendly error messages. This is an alternative to throwing exceptions.
trigger AccountTrigger on Account (before insert) {
for (Account acc : Trigger.new) {
if (acc.Name == null) {
acc.addError('Account Name cannot be null.');
}
}
}
When addError() is called, it does not throw a traditional exception. Instead, it causes the DML operation to fail for that record, and if called from a trigger invoked via standard DML, a DmlException is thrown to the calling code.
Exam Tips: Answering Questions on Exception Handling in Apex
Tip 1: Know Which Exceptions Cannot Be Caught
The exam frequently tests whether you know that LimitException cannot be caught. If a question asks how to handle governor limit violations, the answer is to write code that prevents hitting the limit in the first place — not to use try-catch.
Tip 2: Understand the Difference Between DML Statements and Database Methods
This is one of the most heavily tested topics. Standard DML statements throw DmlException on failure. Database methods with allOrNone = false allow partial processing and return result objects instead of throwing exceptions. If a question scenario requires partial success, the answer involves Database methods.
Tip 3: Remember Catch Block Ordering
More specific exception types must be caught before the generic Exception type. If a question shows catch blocks in the wrong order, the code either won't compile or the specific catch block will be unreachable.
Tip 4: Custom Exception Naming Convention
Custom exception classes must end with the word 'Exception'. If a question shows a custom exception class named 'MyCustomError' that extends Exception, it will not compile.
Tip 5: Know the Exception Methods
Be familiar with getMessage(), getTypeName(), getLineNumber(), and especially the DmlException-specific methods like getDmlMessage() and getNumDml(). Questions may ask which method to use to retrieve error details from a failed DML operation.
Tip 6: Understand try-catch-finally Execution Flow
The finally block always executes, whether or not an exception was thrown, and whether or not it was caught. If a question asks what the output of a code snippet is, trace through the try, catch, and finally blocks carefully.
Tip 7: Savepoints and Rollbacks
Understand that Database.setSavepoint() and Database.rollback() are used together to undo DML operations. Questions may present scenarios where you need to determine which records are committed after a partial rollback.
Tip 8: addError() in Triggers
Know that addError() is the preferred way to display user-friendly error messages in triggers. It prevents the record from being saved without causing an unhandled exception visible to the end user. Questions may ask about the best practice for showing validation-like error messages from trigger logic.
Tip 9: Read Code Snippets Carefully
Many exam questions present a block of code and ask what happens when it executes. Pay close attention to:
• Whether the query returns zero rows (QueryException for single sObject assignment)
• Whether variables might be null (NullPointerException)
• Whether DML is inside or outside the try block
• Whether the catch block catches the correct exception type
Tip 10: Distinguish Between Compile-Time and Runtime Errors
Exception handling only applies to runtime errors. Compile-time errors (syntax errors, type mismatches) are caught by the compiler and cannot be handled with try-catch. If a question presents a syntax error and asks which exception is thrown, the answer is that the code won't compile at all.
Tip 11: Exception Handling and Asynchronous Apex
Remember that unhandled exceptions in asynchronous Apex (future methods, batch, queueable) do not surface to the user in the same way as synchronous code. In Batch Apex, if the execute method throws an unhandled exception, that particular batch chunk fails but subsequent chunks continue processing. Know that the finish method still runs even if some execute invocations fail.
Summary
Exception handling in Apex is about writing resilient code that anticipates failures and manages them gracefully. Master the try-catch-finally syntax, know the built-in exception types (especially DmlException, QueryException, NullPointerException, and LimitException), understand the difference between standard DML and Database methods, and practice reading code snippets to predict execution flow. These skills will not only help you pass the Platform Developer 1 exam but also make you a more effective Salesforce developer in real-world scenarios.
🎓 Unlock Premium Access
Salesforce Certified Platform Developer I + ALL Certifications
- 🎓 Access to ALL Certifications: Study for any certification on our platform with one subscription
- 2750 Superior-grade Salesforce Certified Platform Developer I practice questions
- Unlimited practice tests across all certifications
- Detailed explanations for every question
- PD1: 5 full exams plus all other certification exams
- 100% Satisfaction Guaranteed: Full refund if unsatisfied
- Risk-Free: 7-day free trial with all premium features!