Sunday, February 2, 2025

What is throw new CustomException() in Salesforce?

What is a Custom Exception?

In Apex, an exception is an error condition that can be thrown to interrupt normal program flow. By default, Salesforce provides common exceptions like DmlException, QueryException, etc. However, sometimes you may want to define your own exception types that are specific to your application’s business logic. This is where custom exceptions come in.

A custom exception extends the Exception class and allows you to define your own error message, and optionally, methods to manipulate or log information specific to the error.


Why Use Custom Exceptions?

  • Separation of Concerns: Custom exceptions let you define specific error cases that your code handles, isolating errors for easy troubleshooting.
  • Meaningful Error Messages: You can include custom messages that provide more context about what went wrong.
  • Clearer Logic: With custom exceptions, you can add specific logic that handles different error types in a precise manner.

Basic Syntax:

To define a custom exception, you create a class that extends the Exception class, like so:

apex

public class MyCustomException extends Exception { // You can add custom fields or methods if needed }

Once the exception is defined, you can throw it using throw new MyCustomException('Error message'), and it can be caught in a try-catch block.


Example 1: Simple Custom Exception

Custom Exception Class

apex

public class InvalidAccountException extends Exception {}

Apex Class with Custom Exception

apex

public class AccountService { public static void createAccount(String accName) { if (String.isBlank(accName)) { throw new InvalidAccountException('Account Name cannot be blank.'); } // Code to create an account... } }

Test Class for Custom Exception

In the test class, you can simulate an error condition that will trigger the exception.

apex

@isTest public class AccountServiceTest { @isTest static void testInvalidAccountName() { try { // This should trigger the InvalidAccountException because the account name is blank AccountService.createAccount(''); System.assert(false, 'Expected InvalidAccountException to be thrown'); } catch (InvalidAccountException e) { // Assert that the exception message is correct System.assertEquals('Account Name cannot be blank.', e.getMessage()); } } }

Example 2: Custom Exception with Additional Properties

You can enhance custom exceptions by adding properties or methods to carry additional context information.

Custom Exception with Additional Properties

apex

public class InsufficientBalanceException extends Exception { public Decimal balance { get; set; } // Constructor that accepts balance public InsufficientBalanceException(String message, Decimal balance) { super(message); this.balance = balance; } }

Apex Class Using This Exception

apex

public class BankService { public static void withdraw(Decimal amount, Decimal balance) { if (amount > balance) { throw new InsufficientBalanceException('Insufficient balance for withdrawal.', balance); } // Code to process the withdrawal... } }

Test Class for the Enhanced Custom Exception

apex

@isTest public class BankServiceTest { @isTest static void testInsufficientBalance() { Decimal accountBalance = 100.00; Decimal withdrawalAmount = 200.00; try { // This should trigger the InsufficientBalanceException BankService.withdraw(withdrawalAmount, accountBalance); System.assert(false, 'Expected InsufficientBalanceException to be thrown'); } catch (InsufficientBalanceException e) { // Assert that the exception message and balance are correct System.assertEquals('Insufficient balance for withdrawal.', e.getMessage()); System.assertEquals(accountBalance, e.balance); } } }

Example 3: Custom Exception with Logging

In some cases, you may want to log the exception details to a custom object for auditing purposes. You can include such logic in your custom exception class.

Custom Exception with Logging

apex

public class DatabaseException extends Exception { public String query { get; set; } public DatabaseException(String message, String query) { super(message); this.query = query; } // Log the exception to a custom object for tracking public void logToDatabase() { DatabaseErrorLog__c errorLog = new DatabaseErrorLog__c( Error_Message__c = this.getMessage(), Query__c = this.query, CreatedDate__c = System.now() ); insert errorLog; } }

Apex Class Using This Exception

apex

public class DataService { public static void executeQuery(String query) { try { // Simulate a query execution failure throw new DatabaseException('Query failed due to unknown reasons', query); } catch (DatabaseException e) { // Log the error in a custom object e.logToDatabase(); throw e; // Re-throw to propagate the exception if needed } } }

Test Class for the Logging Custom Exception

apex

@isTest public class DataServiceTest { @isTest static void testDatabaseExceptionLogging() { String query = 'SELECT Id FROM Account WHERE Name = "NonExistentAccount"'; try { DataService.executeQuery(query); System.assert(false, 'Expected DatabaseException to be thrown'); } catch (DatabaseException e) { // Assert that the custom exception message is correct System.assertEquals('Query failed due to unknown reasons', e.getMessage()); // Verify the error log was created List<DatabaseErrorLog__c> logs = [SELECT Id FROM DatabaseErrorLog__c WHERE Query__c = :query]; System.assertEquals(1, logs.size(), 'Error log should be created'); } } }

Example 4: Custom Exception with Multiple Catch Blocks

If your application needs to handle multiple types of exceptions (e.g., DmlException, QueryException, etc.), you can create several custom exceptions to handle specific cases.

Custom Exception for DML Errors

apex

public class CustomDmlException extends Exception { public CustomDmlException(String message) { super(message); } }

Apex Code Handling DML Exceptions

apex

public class AccountService { public static void insertAccount(Account acc) { try { insert acc; } catch (DmlException e) { throw new CustomDmlException('DML operation failed: ' + e.getMessage()); } } }

Test Class for DML Exception

apex
@isTest public class AccountServiceTest { @isTest static void testCustomDmlException() { Account invalidAccount = new Account(); // Missing required Name field try { AccountService.insertAccount(invalidAccount); System.assert(false, 'Expected CustomDmlException to be thrown'); } catch (CustomDmlException e) { System.assert(e.getMessage().contains('DML operation failed'), 'Error message should contain DML failure'); } } }

Summary of Key Benefits of Custom Exceptions:

  1. Clarity in Error Handling: Custom exceptions provide more meaningful error messages specific to your business logic.
  2. Contextual Information: You can pass additional context (e.g., query, balance) with custom exceptions.
  3. Custom Handling: You can add logic to handle exceptions more gracefully, like logging, custom alerts, etc.
  4. Better Maintainability: By naming exceptions appropriately, you make the code easier to maintain and debug.

By using custom exceptions, you can write more efficient, understandable, and maintainable Apex code. They help ensure that specific errors are caught and handled in a way that is relevant to your application’s needs.