How to create a custom exception
Short answer
Create a class that extends RuntimeException and pass the message to the parent constructor:
class InsufficientFundsException extends RuntimeException {
InsufficientFundsException(String message) {
super(message);
}
}
void withdraw(int balance, int amount) {
if (amount > balance) {
throw new InsufficientFundsException("Need " + amount + ", have " + balance);
}
}
void main() {
try {
withdraw(100, 250);
} catch (InsufficientFundsException e) {
IO.println("Error: " + e.getMessage());
}
}Output:
Error: Need 250, have 100Checked or unchecked
A subclass of RuntimeException is unchecked: the compiler does not require handling it. A subclass of Exception is checked: the method must declare it in throws, and the caller must handle it:
class ConfigException extends Exception {
ConfigException(String message) {
super(message);
}
}
String readSetting(String key) throws ConfigException {
throw new ConfigException("Missing setting: " + key);
}
void main() {
try {
readSetting("db.url");
} catch (ConfigException e) {
IO.println(e.getMessage());
}
}Output:
Missing setting: db.urlThe cause
If the exception happened because of another one, pass the original as the second argument — it is kept in getCause():
class ImportException extends RuntimeException {
ImportException(String message, Throwable cause) {
super(message, cause);
}
}
void main() {
try {
try {
Integer.parseInt("12x");
} catch (NumberFormatException e) {
throw new ImportException("Bad row 7", e);
}
} catch (ImportException e) {
IO.println(e.getMessage());
IO.println(e.getCause().getMessage());
}
}Output:
Bad row 7
For input string: "12x"Extra data
An exception can hold fields — for example, an error code for an API response:
class ApiException extends RuntimeException {
private final int status;
ApiException(int status, String message) {
super(message);
this.status = status;
}
int status() {
return status;
}
}
void main() {
try {
throw new ApiException(404, "Order not found");
} catch (ApiException e) {
IO.println(e.status() + " " + e.getMessage());
}
}Output:
404 Order not foundCommon mistake
Extending Exception but not declaring it in throws. The compiler refuses to build such code:
class ConfigException extends Exception {
ConfigException(String message) {
super(message);
}
}
void load() {
throw new ConfigException("no file");
}
void main() {
load();
}Output:
Main.java:8: error: unreported exception Main.ConfigException; must be caught or declared to be thrownFunctions used in this recipe
- throw — Throws an exception and stops the method.
- throws — Declares which checked exceptions a method may throw.
- RuntimeException — The base class of unchecked exceptions — bugs in program logic.
- Throwable.getMessage() — Returns the message text of an exception.