try marks code that may fail, catch handles specific exceptions, finally always runs — and try-with-resources closes resources automatically, in reverse order, without losing exceptions.
Anatomy
public class Main {
static void run(String input) {
try {
System.out.println("parsing " + input);
int n = Integer.parseInt(input);
System.out.println("100 / n = " + 100 / n);
} catch (NumberFormatException | ArithmeticException e) { // multi-catch
System.out.println("bad input: " + e.getClass().getSimpleName());
} finally {
System.out.println("finally"); // always
}
}
public static void main(String[] args) {
run("4");
run("0");
run("x");
}
}parsing 4
100 / n = 25
finally
parsing 0
bad input: ArithmeticException
finally
parsing x
bad input: NumberFormatException
finallyCatch blocks are tried top to bottom; the first matching type wins.
A subclass catch must come before its superclass —
catch (Exception e)thencatch (IOException e)doesn't compile (unreachable).In a multi-catch
A | B, the types can't be related by inheritance andeis implicitlyfinal.tryneeds at least onecatchor afinally(or resources).
finally always runs — even after return
public class Main {
static int value() {
try {
return 1;
} finally {
System.out.println("finally runs before the method returns");
}
}
@SuppressWarnings("finally")
static int overridden() {
try {
throw new RuntimeException("lost!");
} finally {
return 2; // discards the exception AND any earlier return
}
}
static int snapshot() {
int x = 10;
try {
return x; // return value (10) is saved here
} finally {
x = 99; // changing x doesn't affect it
}
}
public static void main(String[] args) {
System.out.println(value());
System.out.println(overridden());
System.out.println(snapshot());
}
}finally runs before the method returns
1
2
10try-with-resources
Any object implementing AutoCloseable (or Closeable) declared in the try (…) header is closed automatically when the block ends — normally or by exception. Resources close in reverse order of declaration.
public class Main {
record Res(String name) implements AutoCloseable {
Res { System.out.println("open " + name); }
@Override public void close() { System.out.println("close " + name); }
}
public static void main(String[] args) {
try (Res db = new Res("db"); Res file = new Res("file")) {
System.out.println("working with " + db.name() + " and " + file.name());
throw new IllegalStateException("failure");
} catch (IllegalStateException e) {
System.out.println("caught " + e.getMessage() + " (resources already closed)");
} finally {
System.out.println("finally");
}
}
}open db
open file
working with db and file
close file
close db
caught failure (resources already closed)
finallySuppressed exceptions
If the body throws and close() throws, the body's exception is the one propagated; the close exception is attached to it as suppressed instead of replacing it (which is what a hand-written finally { close(); } would do).
public class Main {
static class Conn implements AutoCloseable {
@Override public void close() { throw new IllegalStateException("close failed"); }
}
public static void main(String[] args) {
try (Conn c = new Conn()) {
throw new RuntimeException("query failed");
} catch (RuntimeException e) {
System.out.println("primary: " + e.getMessage());
for (Throwable s : e.getSuppressed())
System.out.println("suppressed: " + s.getMessage());
}
}
}primary: query failed
suppressed: close failedBefore and after
Does finally run if there's a return in try?
When does finally NOT execute?
What are suppressed exceptions?
In what order are resources closed?