Skip to content

Exception Handling

Don't be afraid of throwing Exceptions or leaving them uncaught

Code just cannot cover every possible kind of Exception, that's why they're called exceptions. Your code should react on exceptions you know that could occur, but be able to deal with exceptions that remain uncaught. Your application should have a global exception handler for these cases (which would be, for example, serving an HTTP error page with a Status Code 500).

try {
    try {
        url = new Url(aUrl);
    } catch (SchemeMissingException e) {
        url = new Url("https://"+aUrl);
    } 
} catch (MalformedUrlException e) {
    throw new ValidationException("The given URL was invalid");
}
// if `new Url` still throws an exception we didn't expect here
// the global exception handler would fetch that.

Status Flags

Exception handling via status flags should be avoided.

Stacktrace Output

Exceptions being logged should contain information that allows diagnostics afterwards. This could be the stack trace for example.

Context-specific Exceptions

Context, product, library specific exceptions should not leak out of their component (e.g. "Error connecting to the database"). Instead they should be caught and rethrown or wrapped in a new exception, maintaining the context.

try {
    new HttpConnection();
} catch (HttpTransportException e) {
    throw new ServiceException("Upstream service could not be called", e);
}

See also the Law of Demeter.

Custom Exceptions

Custom Exceptions must be handled consistently across the application.