Exceptions note errors and other events that disrupt the normal flow of code execution. throw statements can be used to generate exceptions, while try, catch, and finally can be used to gracefully recover from an exception.
When an exception occurs, code execution halts and any DML operations that were processed prior to the exception are rolled back and aren’t committed to the database. Exceptions get logged in debug logs. For unhandled exceptions, that is, exceptions that the code doesn’t catch, Salesforce sends an email to the developer with the organization ID and user ID of the running user, as well as the exception message.
If you run into an exception that occurred in Apex code while using the standard user interface, an error message appears on the page showing you the text of the unhandled exception as shown below:
Throw Statements
A throw statement allows you to signal that an error has occurred. To throw an exception, use the throw statement and provide it with an exception object to provide information about the specific error. For example:
throw exceptionObject;
Try, Catch, and Finally Statements
Apex uses try, catch and finally statements to handle exceptions. Here is an example of what these statements look like and the order in which they should be written.
try {
// Perform some database operations that
// might cause an exception.
} catch(DmlException e) {
// DmlException handling code here.
} catch(Exception e) {
// Generic exception handling code here.
} finally {
// Perform some clean up.
}
The try statement identifies a block of code in which an exception can occur. If you have code that you think could generate an exception, wrap this section of your code in a try block, and add a catch block after it. Only exceptions thrown from the code wrapped in the try block are handled by the catch block.
The catch statement identifies a block of code that handles a particular type of exception. In the previous example, notice that there are two catch statements. You can have as many catch statements as you like, one for each exception type you want to catch.
The finally statement is optional and gets executed after the catch block executes. Code in the finally block always executes regardless of the type of exception that was thrown and handled. You can add any final clean-up code here.
Built-In Exceptions
Apex provides a number of exception types that the runtime engine throws if errors are encountered during execution.
DmlException :-Any problem with a DML statement, such as an insert statement missing a required field on a record.
ListException :- Any problem with a list, such as attempting to access an index that is out of bounds.Try out some code that does some things on purpose to cause this exception to be thrown. Execute the following:
try {
List<Integer> li = new List<Integer>();
li.add(15);
// This list contains only one element,
// but we're attempting to access the second element
// from this zero-based list.
Integer i1 = li[0];
Integer i2 = li[1]; // Causes a ListException
} catch(ListException le) {
System.debug('The following exception has occurred: ' + le.getMessage());
}
In the previous code snippet, we create a list and add one element to it. Then, we attempt to access two elements, one at index 0, which exists, and one at index 1, which causes a ListException because no element exists at this index. This exception is caught in the catch block. The System.debug statement in the catch block writes the following to the debug log: The following exception has occurred: List index out of bounds: 1.
NullPointerException:- Any problem with dereferencing a null variable.
Try out some code that does some things on purpose to cause this exception to be thrown. Execute the following:
try {
String s;
Boolean b = s.contains('abc'); // Causes a NullPointerException
} catch(NullPointerException npe) {
System.debug('The following exception has occurred: ' + npe.getMessage());
}
we create a String variable named s but we don’t initialize it to a value, hence, it is null. Calling
the contains method on our null variable causes a NullPointerException. The exception is caught in our catch block and this is what is written to the debug log: The following exception has occurred: Attempt to de-reference a null object.
QueryException :-Any problem with SOQL queries, such as assigning a query that returns no records or more than one record to a singleton sObject variable.
SObjectException :-Any problem with sObject records, such as attempting to change a field in an update statement that can only be changed during insert.
try {
Merchandise__c m = [SELECT Name FROM Merchandise__c LIMIT 1];
// Causes an SObjectException because we didn't retrieve
// the Total_Inventory__c field.
Double inventory = m.Total_Inventory__c;
} catch(SObjectException se) {
System.debug('The following exception has occurred: ' + se.getMessage());
}
Exception Methods
Some exception types, such as DmlException, have specific exception methods that apply to only them:
getDmlFieldNames(Index of the failed record): Returns the names of the fields that caused the error for the specified failed record.
getDmlId(Index of the failed record): Returns the ID of the failed record that caused the error for the specified failed record
getDmlMessage(Index of the failed record): Returns the error message for the specified failed record
getNumDml: Returns the number of failed records.
Merchandise__c m1 = new Merchandise__c(
Name='Coffeemaker',
Description__c='Kitchenware',
Price__c=25,
Total_Inventory__c=1000);
// Missing the Price and Total_Inventory fields
Merchandise__c m2 = new Merchandise__c(
Name='Coffeemaker B',
Description__c='Kitchenware');
// Missing all required fields
Merchandise__c m3 = new Merchandise__c();
Merchandise__c[] mList = new List<Merchandise__c>();
mList.add(m1);
mList.add(m2);
mList.add(m3);
try {
insert mList;
} catch (DmlException de) {
Integer numErrors = de.getNumDml();
System.debug('getNumDml=' + numErrors);
for(Integer i=0;i<numErrors;i++) {
System.debug('getDmlFieldNames=' + de.getDmlFieldNames(i));
System.debug('getDmlMessage=' + de.getDmlMessage(i));
}
}
Creating Custom Exceptions
Since you can’t throw built-in Apex exceptions but can only catch them, you can create custom exceptions to throw in your methods. That way, you can also specify detailed error messages and have more custom error handling in your catch blocks. To create your custom exception class, extend the built-in Exception class and make sure your class name ends with the word Exception. Append extends Exception after your class declaration as follows.
public class MyException extends Exception {}
EX:-
Public class ContactException extends Exception{}
public class ContactUtility {
public static void mainProcessing() {
try {
insertContact();
} catch(ContactException me) {
System.debug('Message: ' + me.getMessage());
System.debug('Cause: ' + me.getCause());
System.debug('Line number: ' + me.getLineNumber());
System.debug('Stack trace: ' + me.getStackTraceString());
}
}
public static void insertContact() {
try {
// Insert Contact without required fields
Contact m = new Contact();
insert m;
} catch(DmlException e) {
// Something happened that prevents the insertion
// of Contact objects, so throw a more
// specific exception.
throw new ContactException(
'Contact could not be inserted.', e);
}
}
}