Java
Exception Handling
Custom Exceptions
Java Programming
Code Duplication

How to create a custom exception type in Java?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Creating a custom exception in Java is straightforward, but the important design choice is not the syntax. It is whether the exception should be checked or unchecked, and what extra meaning the custom type adds that a built-in exception would not already communicate.

The Smallest Custom Exception

A custom exception is just a class that extends Exception or RuntimeException.

java
1public class InvalidOrderException extends Exception {
2    public InvalidOrderException(String message) {
3        super(message);
4    }
5}

You can now throw it like any other exception.

java
if (quantity < 0) {
    throw new InvalidOrderException("quantity cannot be negative");
}

That already gives your code a domain-specific error type that callers can catch explicitly.

Checked Versus Unchecked

If you extend Exception, the exception is checked and must be declared or caught.

java
1public void submitOrder(int quantity) throws InvalidOrderException {
2    if (quantity < 0) {
3        throw new InvalidOrderException("quantity cannot be negative");
4    }
5}

If you extend RuntimeException, the exception is unchecked.

java
1public class InvalidOrderStateException extends RuntimeException {
2    public InvalidOrderStateException(String message) {
3        super(message);
4    }
5}

A common rule of thumb is:

  • use checked exceptions for recoverable conditions the caller is expected to handle
  • use unchecked exceptions for programming errors or invalid states the caller usually cannot fix locally

Add Standard Constructors

In real code, it is common to provide more than just a message constructor.

java
1public class InvalidOrderException extends Exception {
2    public InvalidOrderException() {
3        super();
4    }
5
6    public InvalidOrderException(String message) {
7        super(message);
8    }
9
10    public InvalidOrderException(String message, Throwable cause) {
11        super(message, cause);
12    }
13
14    public InvalidOrderException(Throwable cause) {
15        super(cause);
16    }
17}

The cause constructors matter when your exception wraps a lower-level failure while still presenting a more meaningful domain-level type.

Add Extra Fields Only When They Truly Help

Sometimes you want more structure than a message string.

java
1public class ValidationException extends Exception {
2    private final String fieldName;
3
4    public ValidationException(String fieldName, String message) {
5        super(message);
6        this.fieldName = fieldName;
7    }
8
9    public String getFieldName() {
10        return fieldName;
11    }
12}

This can be useful if callers need to inspect machine-readable details. But avoid stuffing exceptions with large amounts of business data unless the extra fields genuinely improve handling.

Use Specific Types To Improve Error Handling

Catching a custom type can be much clearer than catching a generic Exception.

java
1try {
2    submitOrder(-1);
3} catch (InvalidOrderException ex) {
4    System.out.println("Order rejected: " + ex.getMessage());
5}

That makes the API contract clearer and keeps error handling closer to domain meaning.

Naming Conventions

Custom exception names usually end with Exception. That is not technically required, but it makes the code easier to read.

Examples:

  • 'ConfigurationException'
  • 'PaymentFailedException'
  • 'UnsupportedFormatException'

The point is to name the error condition, not the code path where it happened.

Common Pitfalls

The most common mistake is creating a custom exception when an existing JDK exception already says the right thing. Another is making every custom exception checked even when the caller has no realistic recovery action. Developers also often forget to include a constructor that accepts a cause, which makes exception chaining harder. Finally, a custom type should communicate domain meaning; if it is named vaguely, it adds boilerplate without adding clarity.

Summary

  • Create a custom exception by extending Exception or RuntimeException.
  • The real design choice is checked versus unchecked behavior.
  • Include message and cause constructors in practical code.
  • Add extra fields only when they improve handling or diagnostics.
  • Use custom exceptions when they make the API's error meaning clearer than built-in types would.

Course illustration
Course illustration

All Rights Reserved.