Java: Custom Exception

You create a custom exception by extending Exception, directly or indirectly. Technically speaking you could extend any Throwable, but ordinary programs should stick to the Exception hierarchy. See Java Exception Types.

class MyException extends Exception {
    // ...
This can be used as any other exception:
try {
    throw new MyException();
} catch (MyException e) {
    System.out.println("Caught custom exception.");

It’s also customary to allow clients to specify a message and/or cause by overriding one or more Throwable constructors. See the “real world” example at the end of the article.

Which class to extend?

If you extend RuntimeException your exception will be an unchecked exception. Otherwise it will be a checked exception.

This is an important decision and you should read the following two articles to understand the implications.

Use a standard exception if possible

By reusing exceptions from the standard API, either by extending it or by using it off the shelf, you get two benefits:

  • As always with code reuse, you end up with less code to test and maintain

  • It make your API easier to understand, as most programmers are already familiar with the semantics of the standard exceptions

Make sure to always read the Javadoc of the exception you intend to use. Even though an exception may have a generic and fitting name, it may be intended for something specific and entirely different. Don’t use a ZipException for malformed Zip Codes, or an InvalidAddress (which belongs to the CORBA package) for invalid email addresses.

Real World Example

Here’s an example that follows the above mentioned best practices.

Example: The exception below is thrown when the application fails to save the document to disk.
  • It reuses the well known IOException from the API
  • It allows clients to specify message and cause, and
  • It includes information useful when handling the exception
import java.nio.file.Path;
public class SaveDocException extends IOException {
    private final Path path;
    public SaveDocException(Path path) {
        this(path, null, null);
    public SaveDocException(Path path,
                            String msg) {
        this(path, msg, null);
    public SaveDocException(Path path,
                            Throwable cause) {
        this(path, null, cause);
    public SaveDocException(Path path,
                            String msg,
                            Throwable cause) {
        super(msg, cause);
        this.path = path;
    public Path getPath() {
        return path;