finally, try-with-resources & multi-catch
◈ 6 cardsGuaranteed cleanup, automatic resource closing, and handling several exception types at once.
finally: cleanup that always runs
Some code must run no matter what — close a file, release a lock, restore a flag — whether the try succeeded, threw, or was exited early. A finally block attached to a try runs in all three cases:
try {
risky();
} catch (IOException e) {
System.out.println("failed: " + e.getMessage());
} finally {
System.out.println("cleanup"); // runs whether or not risky() threw
}
The finally runs after the try completes normally, after a matching catch runs, and even if an exception propagates out with no matching catch (it runs on the way out). This is where you put the cleanup that cannot be skipped.
try-with-resources: cleanup done for you
Manual cleanup is easy to get wrong — forget the close(), or put it in the wrong place, and you leak file handles or sockets. Java's try-with-resources declares the resource in parentheses after try; any object that implements AutoCloseable is closed automatically when the block ends, success or failure:
try (BufferedReader in = new BufferedReader(new FileReader("examples1.txt"))) {
String line = in.readLine();
System.out.println(line);
} // in.close() called automatically here, even if readLine() threw
There is no explicit close() and no finally — the language inserts the close for you, in the correct reverse order if you declare several resources separated by ;. This is the modern, preferred way to handle files and streams (you will use it throughout Module 8's I/O work).
Multi-catch: one handler, several types
When two or more exception types need the same recovery, repeating the handler is noise. Multi-catch combines them with |:
try {
parseAndRun(file);
} catch (IOException | ControllerException e) {
System.out.println("aborting: " + e.getMessage());
}
The variable e is effectively final and its static type is the nearest common supertype, so you may call only methods common to all the listed types (getMessage() is always safe — it's on Throwable). The caught types must not be subclasses of one another (you can't write IOException | FileNotFoundException — the broader one already covers the narrower).
Worked example — read an event file safely
try (Scanner sc = new Scanner(new File("examples1.txt"))) {
while (sc.hasNextLine()) {
System.out.println(sc.nextLine());
}
} catch (FileNotFoundException | IllegalStateException e) {
System.out.println("could not read events: " + e.getMessage());
}
Scanner implements AutoCloseable, so it is closed when the block ends regardless of how it ends. If the file is missing, the constructor throws FileNotFoundException; if something misuses a closed scanner, IllegalStateException — both land in the single multi-catch handler. No manual finally { sc.close(); } is needed.