Detailed explanation
A custom exception is a Java exception class that you define to represent an application-specific failure. Instead of reporting every failure as a generic Exception or RuntimeException, you give the condition a meaningful type, such as InsufficientFundsException or InvalidOrderStateException. This makes calling code easier to understand and allows it to catch a particular failure without inspecting message text. Custom exceptions are useful when an existing standard exception does not describe the problem adequately; they are not needed for every validation check.
To create one, extend Exception for a checked exception or RuntimeException for an unchecked exception. For example: class InsufficientFundsException extends RuntimeException { InsufficientFundsException(String message) { super(message); } }. You can then raise it with: throw new InsufficientFundsException("Balance too low");. The call to super(message) passes the description to the superclass, making it available through getMessage(). In a reusable API, the class and its constructors are usually public. A public top-level class must be placed in a file with the same name, such as InsufficientFundsException.java.
The superclass determines the compiler's handling rules. If your class extends Exception directly, a method that lets it escape must declare it using throws, and callers must catch it or declare it themselves. If it extends RuntimeException, neither catching nor declaring it is required by the compiler. Choose checked exceptions when the API deliberately requires callers to acknowledge a failure; choose unchecked exceptions when mandatory handling would not suit the contract, often for invalid usage or violated preconditions. Whether callers can recover is a useful consideration, not an absolute rule.
At runtime, throwing a custom exception follows normal Java exception handling: execution leaves the current path, and Java searches for a compatible catch block up the call stack. The exception normally carries a stack trace and can preserve an underlying cause through a constructor calling super(message, cause). You may also add immutable fields, such as requiredAmount and availableBalance, with getters. Interviewers generally look for correct inheritance, the checked-versus-unchecked distinction, proper constructor delegation, and a realistic reason for introducing a new exception type.
Key points to remember
- A custom exception gives a domain-specific failure a meaningful, catchable Java type.
- Extend Exception for a checked exception or RuntimeException for an unchecked exception.
- Pass the error message to super(message), and preserve underlying failures with super(message, cause).
- Use throw to raise an exception; checked exceptions that escape a method must appear in its throws declaration.
- Add useful immutable context fields when needed, but prefer existing standard exceptions when they fit.
Common mistakes candidates make
- Saying that unchecked exceptions cannot be caught, or that all custom exceptions are checked.
- Confusing throw, which raises an exception, with throws, which declares exceptions in a method signature.
- Wrapping an exception without preserving its cause, which loses valuable debugging context.
Likely follow-up questions
How would you make InsufficientFundsException checked?
Change its superclass from RuntimeException to Exception. A method that throws it without handling it must declare throws InsufficientFundsException, and its caller must catch it or propagate it.
How do you preserve the original exception when wrapping it?
Provide a constructor such as InsufficientFundsException(String message, Throwable cause) { super(message, cause); }. Pass the original exception as the cause so diagnostic tools and getCause() can expose the underlying failure.
When should you avoid creating a custom exception?
Avoid introducing one when a standard exception, such as IllegalArgumentException or IllegalStateException, already expresses the failure clearly. A custom type is more useful when callers need to distinguish a domain-specific condition or access structured error details.
Interview tip: Start with the definition, show a tiny class and throw statement, then explain how choosing Exception or RuntimeException changes the caller's obligations.
