Skip to main content

SF-0318 · Concept · Easy

What are exception statements?

✓ Verified by Vikas Singhal · Last reviewed 5/17/2026 · Updated for Spring '26

Exception statements are the four Apex keywords that drive error handling: try, catch, finally, and throw. Together they let you isolate risky work, react to specific failures, run cleanup unconditionally, and raise your own errors.

The four keywords

KeywordJob
tryWraps a block of code that might throw
catchHandles a specific exception type. You can have multiple, ordered specific-to-general
finallyAlways runs after try/catch — success, exception, or even return
throwRaises an exception (a built-in type or your own custom class)

Full shape

try {
    // risky work
    Account a = [SELECT Id FROM Account WHERE Name = 'NoSuch' LIMIT 1];
    insert new Contact(LastName = 'X', AccountId = a.Id);
} catch (QueryException qe) {
    System.debug('Account lookup failed: ' + qe.getMessage());
} catch (DmlException de) {
    System.debug('Contact insert failed: ' + de.getMessage());
} catch (Exception e) {
    System.debug('Other failure: ' + e.getMessage());
} finally {
    System.debug('Always runs — release locks, close streams, etc.');
}

Order matters: specific exception types must appear before generic ones. catch (Exception e) is the wildcard — if you put it first, more specific catches below it are dead code, and the compiler flags it.

Throwing your own

public class ValidationException extends Exception {}

public class AccountService {
    public static void validate(Account a) {
        if (a.Name == null) {
            throw new ValidationException('Account Name is required');
        }
    }
}

Custom exception classes simply extend Exception — no method overrides required. They give you a typed catch block in the caller, which is much cleaner than parsing message strings.

Rethrowing

Sometimes you catch an exception just to log it, then re-throw so the caller still sees the failure:

try {
    riskyWork();
} catch (Exception e) {
    Logger.log(e);
    throw e;
}

You can also wrap a low-level exception in a higher-level one and preserve the cause:

} catch (DmlException de) {
    throw new AccountServiceException('Failed to save account', de);
}

What finally is for

The classic uses on the platform:

  • Resetting Test.setCurrentPage(...) or any other test-only state
  • Releasing a manually-acquired lock (rare in Apex)
  • Logging exit conditions so debug logs are self-contained
  • Re-enabling a triggers-disabled flag

finally runs even if a return statement fires inside try. The one thing that won’t run a finally is a LimitException (governor limit) — the runtime is killing the transaction outright.

Common follow-ups

  • Can you have try without catch? — Only if you have finally. try {} finally {} is legal; try {} alone is not.
  • Multiple catches per type? — No, one catch per exception type per try.
  • Catching LimitException? — Not catchable in normal code paths.

Verified against: Apex Developer Guide — Exception Statements. Last reviewed 2026-05-17 for Spring ‘26.