Java Exceptions β try-catch, throw, throws, checked vs unchecked
Exceptions are Java's mechanism for reporting that something went wrong β a missing file, a division by zero, a null where an object was expected. The compiler enforces handling for checked exceptions; unchecked ones (subclasses of RuntimeException) can be thrown and caught freely.
The exception hierarchy
Throwable
βββ Error // JVM problems β don't catch these
β βββ OutOfMemoryError
β βββ StackOverflowError
βββ Exception // your problems
βββ IOException // checked
βββ SQLException // checked
βββ RuntimeException // unchecked
βββ NullPointerException
βββ ArrayIndexOutOfBoundsException
βββ ClassCastException
βββ IllegalArgumentException
try / catch / finally
try {
doRisky();
} catch (FileNotFoundException e) {
log.warn("missing", e);
} catch (IOException | SQLException e) { // multi-catch β Java 7+
log.error("IO or DB", e);
} finally {
cleanup(); // always runs
}
Try-with-resources (Java 7+) β the only safe way to close things
try (var reader = Files.newBufferedReader(path)) {
return reader.readLine();
}
// reader.close() runs automatically β even on exception
Any object implementing AutoCloseable can go in the try resource list. Multiple resources are closed in reverse order.
Checked vs unchecked
| Checked | Unchecked | |
|---|---|---|
| Parent | Exception (not RuntimeException) | RuntimeException |
| Compiler-enforced | Yes β must catch or declare | No |
| Typical use | Recoverable, external I/O, network | Programming bugs, invalid state |
| Example | IOException | NullPointerException |
throw vs throws
// throws β declares exceptions a method can throw (checked only)
public String read(Path p) throws IOException {
if (!Files.exists(p)) {
// throw β actually raises an exception
throw new IllegalArgumentException("missing: " + p);
}
return Files.readString(p);
}
Custom exceptions
public class OrderNotFoundException extends RuntimeException {
private final long orderId;
public OrderNotFoundException(long orderId) {
super("Order not found: " + orderId);
this.orderId = orderId;
}
public long orderId() { return orderId; }
}
Prefer RuntimeException for business-logic failures. Reserve checked exceptions for truly recoverable I/O errors where the caller has a meaningful choice.
Pattern matching for instanceof in catch (Java 21+)
try {
...
} catch (Exception e) {
String msg = switch (e) {
case IOException io -> "IO: " + io.getMessage();
case SQLException sql -> "DB " + sql.getSQLState();
default -> "unknown";
};
}
All sub-topics
try/catch/finally- Try-with-resources
throwthrowsclause- Checked vs unchecked
NullPointerExceptionArrayIndexOutOfBoundsExceptionClassCastExceptionIllegalArgumentExceptionConcurrentModificationException- Custom exceptions
Common mistakes
- Catching
ExceptionorThrowableβ hidesError,RuntimeException, programming bugs. Catch the narrowest type that makes sense. - Empty catch blocks β swallows the problem. At minimum, log it.
- Using exceptions for control flow β they're ~100Γ slower than an
if. Validate up front. - Wrapping without the cause β
throw new MyException("failed")loses the stack. Use the two-arg constructor:new MyException("failed", e).
Try it & related tools
The Java Online Compiler shows full stack traces on uncaught exceptions. For structured error payloads in APIs, the JSON to POJO tool generates error DTO classes.