The try Statement and catch Clauses
A finally clause is the last step of a try statement and runs whether or not an exception occurs and whether or not it is caught.
Why Cleanup Can Be Skipped
Many programs open something outside themselves, such as a file or a network connection, do some work with it, and then have to let it go. The work in the middle is where things go wrong. A connection can drop, a file can be missing, or a user can type something unexpected. When that happens, the code that releases the resource can be skipped entirely if it sits at the end of the normal path. Java offers two tools to prevent that problem: the finally clause and the try-with-resources statement. This article covers both, starting with the try statement and its catch clauses.
Before reading the explanation, study the short program below. It has a try block that deliberately throws an exception, a catch block that reports it, and a finally block that performs cleanup. Decide for yourself what you expect the program to print and in what order.
What do you think happens?
Which lines print, and in what order?
Reveal answer
Opening, then Caught, then Cleanup, then After. The line Working never prints.
Dividing by zero throws an ArithmeticException partway through the try block, so the rest of that block is skipped. The catch clause handles the exception and prints Caught. The finally block then runs as the last step of the statement, and execution continues with the line after the statement.
Opening
Caught
Cleanup
AfterThree Parts of a try Statement
A try statement is a sequence of up to three kinds of parts. It always has a try block, which holds the work that might fail. It can have zero or more catch clauses, each of which handles a particular kind of exception. It can also have one optional finally clause at the very end. The finally clause is attached to the same try statement and is written after any catch clauses. Its statements form the final step of the whole statement, no matter what happened earlier.
Read the diagram from the top. Control can take the path where no exception occurs, the path where an exception occurs and a catch clause handles it, and the path where an exception occurs and no catch clause catches it. The finally block sits on every one of these paths. Notice that the no-exception path and the caught path both reach the finally block, and the uncaught path reaches it too. In the uncaught case, the exception still leaves the statement after the finally block has finished.
Why Cleanup Placement Matters
Consider a program that opens a network connection, communicates over it, and then fails in the middle. The program must still close the connection, because otherwise the connection is left open. Closing a connection is essential cleanup. The general pattern is to obtain a resource, use it, and then release it. The important question is where the release step is placed, because placement decides whether the step is reached when something goes wrong.
The lesson of this pattern is about placement. A cleanup step written after the try statement as an ordinary statement is skipped when an exception escapes the statement, because control leaves the statement before reaching that line. A cleanup step written inside the finally clause is not skipped, because the finally block runs whether or not an exception occurred. The finally clause is therefore the place for steps that must happen regardless of how the work went.
Placing the Release Step
A program opens a connection, sends a request, and the request fails partway through. Where should the close step go so that the connection is released?
- 1Identify the resource
The connection is obtained before the risky work begins, so it must be released no matter how that work ends.
- 2Test a close after the try statement
If the failure is an exception that escapes the statement, control leaves the statement before reaching an ordinary close line that follows it. That line is skipped and the connection stays open.
- 3Move the close into the finally clause
The finally block runs on the success path, on the caught path, and on the uncaught path. Placing the close there means it runs in every case.
The release step belongs in the finally clause. Placed there, it is not skipped when the work fails.
Automatic Closing with try-with-resources
Writing a finally clause for every resource works, but it requires the programmer to remember the cleanup each time. Java offers a shorter form, the try-with-resources statement, which handles the release automatically. The resource is declared in parentheses directly after the word try, and the system takes responsibility for closing it when the statement ends. The form works in three respects, described below.
What AutoCloseable Requires
AutoCloseable is the requirement a resource's class must meet to be used in a try-with-resources statement. The class must implement AutoCloseable, which defines a single close() method with no parameters.
Sending data
Connection closed- The class declares that it implements AutoCloseable.
- The
close()method takes no parameters, as the interface requires. - The programmer never calls
close()in the try statement; the system calls it when the statement ends.
Automatic Close Versus a Manual Close
When an exception occurs in the middle of using a connection, the difference between the two close placements becomes concrete. In the manual version, the close call sits after the work, so the exception skips it. In the try-with-resources version, the system closes the resource when the statement ends, so the close still happens after the exception.
| Feature | finally clause | try-with-resources |
|---|---|---|
| Who writes the release step | The programmer writes whatever cleanup is needed | The system calls close() automatically |
| Requirement on the resource | None beyond the cleanup the programmer writes | The resource's class must implement AutoCloseable |
| Where the resource is declared | Usually outside or before the try statement | In parentheses directly after try, with an initialization |
| Scope of the resource variable | Depends on where it was declared | Local to the try statement |
| Runs when an exception escapes | Yes, the finally block runs | Yes, close() is called at the end of the statement |
Two tools that solve the same problem in different ways
Mistakes Beginners Make
Common mistake Placing the close call after the try statement and assuming it always runs
What it looks liketry { open(); use(); } catch (Exception e) { report(e); } then close(); on the next lineWhy it failsAn exception that escapes the statement leaves before the ordinary close line is reached, so the close is skipped.
Do this insteadPlace the release step in the finally clause, which runs whether or not an exception occurred.
Common mistake Believing the finally block runs only when an exception is caught
What it looks likeAn exception is thrown inside try, and no catch clause matches it.
Why it failsThe finally block runs on the uncaught path too. The source states that it runs whether or not an exception is caught.
Do this insteadExpect the finally block to run first, and then the uncaught exception to propagate outward.
Common mistake Declaring a try-with-resources variable without initializing it
What it looks liketry (Scanner input) { ... }Why it failsThe declaration in parentheses must include an initialization, and the automatic close depends on the variable being successfully initialized.
Do this insteadWrite try (Scanner input = new Scanner(System.in)) { ... }Common mistake Using the resource variable after the try-with-resources statement ends
What it looks liketry (Scanner input = new Scanner(System.in)) { ... } then input.nextLine() after the closing braceWhy it failsThe variable is local to the try statement, so its name is not visible after the statement ends.
Do this insteadDo all the work that needs the resource inside the braces of the try statement.
Common mistake Using a class in try-with-resources that does not implement AutoCloseable
Why it failsThe automatic close depends on the class implementing AutoCloseable and its
close()method.Do this insteadImplement AutoCloseable with a close() method that takes no parameters, or use a finally clause with an explicit cleanup step.
Diagnosing Where Cleanup Ran
When a program produces an unexpected result involving files or connections, a useful question is whether the cleanup ran, and at what point. Because the finally block is the last step of its try statement, a missing or early release points to the statement that contains the cleanup.
- 1Find where the resource was declared, and confirm whether it sits in the parentheses of a try-with-resources statement or outside any try statement.
- 2Identify which statements used the resource, and whether an exception could have interrupted them.
- 3Check whether the close step was in a finally block or was an ordinary statement placed after the try statement.
- 4If the close is an ordinary statement after the try, move it into a finally clause, or switch to try-with-resources if the class implements AutoCloseable.
Practice Tracing a Cleanup Path
A try block opens a connection, then throws an exception before it finishes using the connection. A catch clause prints a message, and a finally clause closes the connection. Without running the program, list the order of the three actions and state whether the connection is closed. Then say what would change if the close call were moved after the try statement as an ordinary statement.
Hints
- Ask which lines are skipped once the exception is thrown.
- Recall that the finally block is the last step of the whole try statement, no matter what happened earlier.
- Think about whether an ordinary statement placed after the try is reached when the exception escapes the statement.
Key Takeaways
- 1A finally clause is the last step of a try statement and runs whether or not an exception occurs and whether or not it is caught.
- 2Cleanup placed in a finally clause is not skipped when an exception escapes, while an ordinary statement placed after the try can be skipped.
- 3A try-with-resources statement declares a resource in parentheses, keeps the variable local to the statement, and calls
close()automatically at the end. - 4The automatic close requires that the resource's class implements AutoCloseable, which defines a single
close()method with no parameters.
At a glance
- A finally clause is the last step of a try statement and runs whether or not an exception occurs and whether or not it is caught.
- Cleanup placed in a finally clause is not skipped when an exception escapes; an ordinary statement placed after the try can be skipped.
- A try-with-resources statement declares a resource in parentheses, keeps it local to the statement, and calls
close()automatically. - The automatic close requires the resource's class to implement AutoCloseable, which defines a single
close()method with no parameters.