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]
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.