Exception Handling in Java: Checked vs Unchecked and try-with-resources
Codevity Admin · 10/25/2026
Codevity Admin · 10/25/2026
Exception handling questions fill a large share of Java interviews, and the details (checked versus unchecked, what finally really does, try-with-resources) are where marks are won or lost.
Throwable
|-- Error serious JVM problems: OutOfMemoryError, StackOverflowError (do not catch these)
|-- Exception
|-- IOException, SQLException, ... checked exceptions
|-- RuntimeException unchecked exceptions
|-- NullPointerException, IllegalArgumentException, ArrayIndexOutOfBoundsException, ...| Checked exceptions | Unchecked exceptions | |
|---|---|---|
| Superclass | Exception (but not RuntimeException) | RuntimeException and its subclasses |
| Compiler check | You must catch them or declare them with throws | No requirement |
| Meant for | Problems a caller can reasonably recover from (a missing file, a network failure) | Programming mistakes (a null argument, a bad index) |
| Examples | IOException, SQLException, FileNotFoundException | NullPointerException, IllegalArgumentException, ClassCastException |
Errors are also unchecked. Do not catch them: the JVM may be in no state to continue.
public class Handling {
public static void main(String[] args) {
try {
Integer.parseInt("abc");
} catch (NumberFormatException e) { // the most specific handler first
System.out.println("Bad number: " + e.getMessage()); // Bad number: For input string: "abc"
} catch (RuntimeException e) { // more general handlers later
System.out.println("Unexpected");
} finally {
System.out.println("always runs"); // always runs
}
try {
Object text = "hi";
Integer wrong = (Integer) text;
} catch (ClassCastException | NullPointerException e) { // multi-catch
System.out.println("caught " + e.getClass().getSimpleName()); // caught ClassCastException
}
}
}catch runs, so put specific exceptions before general ones. The other order does not compile ("exception already caught").A | B) handles unrelated exceptions the same way.throw throws an exception object. throws is part of a method signature and declares what it may throw.finally runs whether or not an exception was thrown, even after a return. It does not run if:
System.exit(...)) or crashes, or the machine loses power,try block never ends (an infinite loop or a deadlock).A return inside finally overrides the earlier return value and even swallows an exception. Avoid it:
public class FinallyTricks {
@SuppressWarnings("finally")
static int test() {
try {
return 1;
} finally {
return 2; // overrides the return value above: do not do this
}
}
public static void main(String[] args) {
System.out.println(test()); // 2
}
}| Name | What it is |
|---|---|
final | A keyword: a variable that cannot be reassigned, a method that cannot be overridden, a class that cannot be extended |
finally | A block that runs after try and catch for cleanup |
finalize() | An old Object method the garbage collector called before reclaiming an object. Deprecated for removal since Java 18: use try-with-resources or Cleaner instead |
Any class that implements AutoCloseable can be declared in the try (...) header. Java closes it automatically, in reverse order of opening, whether the block finishes normally or throws:
The output shows the order: , , , , , then the catch block. The exception from the body is the one that propagates. Exceptions thrown while closing are attached to it as suppressed exceptions (), so nothing is lost. A plain / would let a failure in replace the original exception. See the try-with-resources snippet.
Extend for a checked exception or for an unchecked one, and keep the original as the cause:
open Aopen Bbodyclose Bclose AgetSuppressed()tryfinallyfinallyExceptionRuntimeExceptioncatchExceptionThrowabletry-with-resourcesIllegalArgumentException("amount must be positive")Res.close()throws IOExceptiontrycatchtry-with-resourcespublic class Resources {
public static void main(String[] args) {
try (Res a = new Res("A"); Res b = new Res("B")) {
System.out.println("body");
throw new IllegalStateException("from body");
} catch (IllegalStateException e) {
System.out.println("caught " + e.getMessage());
for (Throwable s : e.getSuppressed()) {
System.out.println("suppressed " + s.getMessage());
}
}
}
}
class Res implements AutoCloseable {
private final String name;
Res(String name) {
this.name = name;
System.out.println("open " + name);
}
@Override
public void close() {
System.out.println("close " + name);
throw new IllegalStateException("close failed " + name);
}
}public class Custom {
public static void main(String[] args) {
try {
load("orders.csv");
} catch (DataLoadException e) {
System.out.println(e.getMessage()); // Could not load orders.csv
System.out.println(e.getCause().getClass().getSimpleName()); // FileNotFoundException
}
}
static void load(String file) throws DataLoadException {
try {
throw new java.io.FileNotFoundException(file);
} catch (java.io.IOException e) {
throw new DataLoadException("Could not load " + file, e); // wrap, keeping the cause
}
}
}
class DataLoadException extends Exception {
DataLoadException(String message, Throwable cause) {
super(message, cause);
}
}