The full picture
int f() {
try { return 1; }
finally { return 2; } // returns 2 — the 1 is discarded
}
int g() {
try { throw new IllegalStateException("REAL cause"); }
finally { return -1; } // exception SWALLOWED — g() just returns -1
}
void h() throws IOException {
InputStream in = open();
try { read(in); } // throws ReadException…
finally { in.close(); } // …close() throws too -> ReadException LOST
} // try-with-resources keeps it + suppresses close()
// Also: System.exit() in try skips finally; finally does run on return/exception,
// but NOT on JVM kill (kill -9) — never put durability logic in finally.- javac even warns on
finallyblocks that can't complete normally — treat that warning as an error. - Cleanup that itself can fail (flush/close) belongs in try-with-resources;
finallyis for the truly non-throwing tidy-up (unlock, MDC clear, timer stop). lock.unlock()in finally is the canonical good use — and pairs with the rule that the lock() call sits before the try.