Custom Exception in Java
Problem
A custom exception is a user-defined class that extends Exception (or RuntimeException) to represent a specific error condition in your own code.
Define a custom exception and throw it when a withdrawal exceeds the account balance.
Java Program
class InsufficientFundsException extends Exception {
InsufficientFundsException(String message) {
super(message); // forwards the message so getMessage() can return it
}
}
public class BankAccount {
// throws clause forces callers to catch or declare this checked exception
static void withdraw(double balance, double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException("Insufficient funds for this withdrawal");
}
System.out.println("Withdrawal successful");
}
public static void main(String[] args) {
try {
withdraw(100.0, 150.0);
} catch (InsufficientFundsException e) {
System.out.println("Error: " + e.getMessage());
}
}
}Output
Core Logic
Sometimes the built-in exceptions don't fit — here a custom checked exception is thrown when a withdrawal breaks the balance rule.
- 1
class InsufficientFundsException extends Exceptioncreates a new checked exception type. - 2Its constructor forwards the message to
super(message), sogetMessage()returns it later. - 3
withdraw()declaresthrows InsufficientFundsException, requiring callers to handle it. - 4When
amount > balance, the method doesthrow new InsufficientFundsException(...)instead of continuing. - 5The caller wraps the call in
try/catchand reads the message back withe.getMessage().
150 from a balance of 100 throws the custom exception, caught and printed as "Error: Insufficient funds for this withdrawal".Key Point: Extending Exception (not RuntimeException) makes this a checked exception — the compiler forces every caller to either catch it or declare it.
Key Concepts
Approach 2: Unchecked Custom Exception
class InsufficientFundsRuntimeException extends RuntimeException {
InsufficientFundsRuntimeException(String message) {
super(message);
}
}
public class BankAccountUnchecked {
// No throws clause needed — RuntimeException is unchecked
static void withdraw(double balance, double amount) {
if (amount > balance) {
throw new InsufficientFundsRuntimeException("Insufficient funds for this withdrawal");
}
System.out.println("Withdrawal successful");
}
public static void main(String[] args) {
try {
withdraw(100.0, 150.0);
} catch (InsufficientFundsRuntimeException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
Output
Core Logic
The same idea works as an unchecked exception too — extend RuntimeException instead, and callers are no longer forced to handle it.
- 1
class InsufficientFundsRuntimeException extends RuntimeExceptionmakes this an unchecked exception. - 2
withdraw()no longer needs athrowsclause — the compiler doesn't require callers to catch or declare unchecked exceptions. - 3The
throwstatement insidewithdraw()is otherwise identical to the checked version. - 4The caller still chooses to wrap the call in
try/catchhere, but it's now optional rather than compiler-enforced.
withdraw(100.0, 150.0) throws the same way as before, but the compiler would have allowed calling it with no try/catch at all.Key Point: Use a checked exception when callers can reasonably be expected to recover (like retrying with a smaller amount); use an unchecked one when the failure represents a programming error or a business rule violation the caller isn't expected to routinely handle.