Wednesday, 29 August 2012

Try, Catch, and Finally Statements - Apex

Apex uses trycatch 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 atry 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.
Order catch statements from specific to generic. All exceptions are considered to be of type Exception, so if you catch the generic Exception type first, the other catch statements won’t execute—only one catch block executes.
In the catch statement, handle the exception received. For example, you can perform some logging, send an email, or do some other processing.
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.

Try It Out

To see an exception in action, execute some code that causes a DML exception to be thrown. Execute the following in the Developer Console:

Merchandise__c m = new Merchandise__c();
insert m;
The insert DML statement in the example causes a DmlException because we’re inserting a merchandise item without setting any of its required fields. This is the exception error that you see in the debug log.
System.DmlException: Insert failed. First exception on row 0; first error: REQUIRED_FIELD_MISSING, Required fields are missing: [Description, Price, Total Inventory]: [Description, Price, Total Inventory]
Next, execute this snippet in the Developer Console. It’s based on the previous example but includes a try-catch block.

try {
    Merchandise__c m = new Merchandise__c();
    insert m;
} catch(DmlException e) {
    System.debug('The following exception has occurred: ' + e.getMessage());
}
Notice that the request status in the Developer Console now reports success. This is because the code handles the exception.
Any statements in the try block occurring after the exception are skipped and aren’t executed. For example, if you add a statement after insert m;, this statement won’t be executed. Execute the following:

try {
    Merchandise__c m = new Merchandise__c();
    insert m;
    // This doesn't execute since insert causes an exception 
    
    System.debug('Statement after insert.');
} catch(DmlException e) {
    System.debug('The following exception has occurred: ' + e.getMessage());
}
In the new debug log entry, notice that you don’t see a debug message of Statement after insert. This is because this debug statement occurs after the exception caused by the insertion and never gets executed. To continue the execution of code statements after an exception happens, place the statement after the try-catch block. Execute this modified code snippet and notice that the debug log now has a debug message of Statement after insert.

try {
    Merchandise__c m = new Merchandise__c();
    insert m;
} catch(DmlException e) {
    System.debug('The following exception has occurred: ' + e.getMessage());
}
// This will get executed 
    
System.debug('Statement after insert.');
Alternatively, you can include additional try-catch blocks. This code snippet has the System.debug statement inside a second try-catch block. Execute it to see that you get the same result as before.

try {
    Merchandise__c m = new Merchandise__c();
    insert m;
} catch(DmlException e) {
    System.debug('The following exception has occurred: ' + e.getMessage());
}

try {
    System.debug('Statement after insert.');
    // Insert other records 
    
}
catch (Exception e) {
    // Handle this exception here 
    
}
The finally block always executes regardless of what exception is thrown, and even if no exception is thrown. Let’s see it used in action. Execute the following:

// Declare the variable outside the try-catch block 
    
// so that it will be in scope for all blocks. 
    
XmlStreamWriter w = null;
try {
    w = new XmlStreamWriter();
    w.writeStartDocument(null, '1.0');
    w.writeStartElement(null, 'book', null);
    w.writeCharacters('This is my book');
    w.writeEndElement(); 
    w.writeEndDocument();

    // Perform some other operations 
    
    String s;
    // This causes an exception because 
    
    // the string hasn't been assigned a value. 
    
    Integer i = s.length();
} catch(Exception e) {
    System.debug('An exception occurred: ' + e.getMessage());
} finally {
    // This gets executed after the exception is handled 
    
    System.debug('Closing the stream writer in the finally block.');
    // Close the stream writer 
    
    w.close();
}
The previous code snippet creates an XML stream writer and adds some XML elements. Next, an exception occurs due to accessing the null String variable s. The catch block handles this exception. Then the finally block executes. It writes a debug message and closes the stream writer, which frees any associated resources. Check the debug output in the debug log. You’ll see the debug message Closing the stream writer in the finally block. after the exception error. This tells you that the finally block executed after the exception was caught.

No comments:

Post a Comment