![]() | |
|
The try-with-resources statement is a try
statement that
declares one or more resources.
A resource is as an object that must be closed after the program is finished with it. The try-with-resources
statement ensures that each resource is closed at the end of the statement. Any object that implements java.lang.AutoCloseable
,
which includes all objects which implement java.io.Closeable
, can be used as a resource:
package java.lang; public interface AutoCloseable { void close() throws Exception; }
The Closeable
interface extends the AutoCloseable
interface. The close()
method of the Closeable
interface throws exceptions of type IOException
while the close()
method of the AutoCloseable
interface
throws exceptions of type Exception
. Consequently, subclasses of the AutoCloseable
interface can override this
behavior of the close()
method to throw specialized exceptions, such as IOException
, or no exception at all.
package java.io; import java.io.IOException; public interface Closeable extends AutoCloseable { public void close() throws IOException; }
The following example reads the first line from a file. It uses an instance of BufferedReader
to read data from the file.
BufferedReader
is a resource that must be closed after the program is finished with it:
static String readFirstLineFromFile(String path) throws IOException { try (BufferedReader br = new BufferedReader(new FileReader(path))) { return br.readLine(); } }
In this example, the resource declared in the try-with-resources statement is a BufferedReader
. The declaration statement appears
within parentheses immediately after the try
keyword. The class BufferedReader
, in Java SE 7 and later, implements
the interface java.lang.AutoCloseable
. Because the BufferedReader
instance is declared in a try-with-resource
statement, it will be closed regardless of whether the try
statement completes normally or abruptly (as a result of the
method BufferedReader.readLine
throwing an IOException
).
Prior to Java SE 7, you can use a finally
block to ensure that a resource is closed regardless of whether the whether the try
statement completes normally or abruptly. The following example uses a finally
block instead of a try-with-resources statement:
static String readFirstLineFromFileWithFinallyBlock(String path) throws IOException { BufferedReader br = new BufferedReader(new FileReader(path)); try { return br.readLine(); } finally { if (br != null) br.close(); } }
However, in this example, if the methods readLine
and close
both throw exceptions, then the method
readFirstLineFromFileWithFinallyBlock
throws the exception thrown from the finally
block; the
exception thrown from the try
block is suppressed. In contrast, in the example readFirstLineFromFile
,
if exceptions are thrown from both the try
block and the try-with-resources statement, then the method
readFirstLineFromFile
throws the exception thrown from the try
block; the exception thrown from the
try-with-resources block is suppressed. In Java SE 7 and later, you can retrieve suppressed exceptions; see the next section
for more information.
You may declare one or more resources in a try-with-resources statement. The following example makes a
copy of a file, using the try-with-resources statement. There are two resources defined in the try
statement,
separated by a semicolon, which are automatically closed when the statement completes:
public static void copyFile(String src, String dest) throws IOException { try (BufferedReader in = new BufferedReader(new FileReader(src)); BufferedWriter out = new BufferedWriter(new FileWriter(dest))) { String line; while((line = in.readLine()) != null) { out.write(line); out.write('\n'); } } // No need to close resources in a "finally" }
NOTE: the close()
methods of resources are called in the OPPOSITE
order of their creation.
NOTE: in try-with-resource statement the catch
and the finally
blocks are
OPTIONAL.
In JDBC 4.1 the java.lang.AutoCloseable
interface is extended by the following interfaces:
java.sql.Connection
java.sql.ResultSet
java.sql.Statement
The following example uses a try-with-resources statement to automatically close a java.sql.Statement
object:
public static void viewTable(Connection con) throws SQLException { String query = "SELECT ... FROM ..."; try (Statement stmt = con.createStatement()) { ResultSet rs = stmt.executeQuery(query); while (rs.next()) { // ... } } catch (SQLException e) { // ... } }
The resource java.sql.Statement
used in this example is part of the JDBC 4.1 and later API.
NOTE: A try-with-resources statement CAN have catch
and finally
blocks just like an ordinary try
statement. In a try-with-resources statement, any catch
or finally
block is run
AFTER the resources declared have been closed.
Making an Auto-Closeable Class
As you know, a try-with-resources statement cannot manage every class. A new interface called java.lang.AutoCloseable
was introduced
in Java SE 7. All it does is provide a void method named close()
that may throw a checked exception (java.lang.Exception
).
Any class willing to participate in try-with-resources statements should implement this interface. It is strongly recommended that implementing
classes and sub-interfaces declare a more precise exception type than java.lang.Exception
, or, even better, declare no exception type
at all if invoking close()
should not fail.
Such close()
methods have been retro-fitted into many classes of the standard Java SE run-time environment , including the
java.io
, java.nio
, javax.crypto
, java.security
, java.util.zip
, java.util.jar
,
javax.net
, and java.sql
packages. The major advantage of this approach is that existing code continues working just as
before, while new code can easily take advantage of the try-with-resources statement.
Consider the following example:
public class AutoCloseableResource implements AutoCloseable { @Override public void close() { System.out.println("in close()"); throw new RuntimeException("Exception in close()"); } public void work() throws Exception { System.out.println("in work()"); throw new Exception("Exception in work()"); } }
public class AutoCloseableTest { public static void main(String[] args) { try (AutoCloseableResource resource = new AutoCloseableResource()) { resource.work(); } catch (Exception e) { e.printStackTrace(); } } }
The AutoCloseableResource
class implements java.lang.AutoCloseable
and can thus be used as part of a try-with-resources
statement, as illustrated in the AutoCloseableTest.main(...)
method. Intentionally, we added some console output, and we throw
exceptions both in the work()
and close() methods of the class. Running the program yields the following output:
in work() in close() java.lang.Exception: Exception in work() at AutoCloseableResource.work(AutoCloseableResource.java:21) at AutoCloseableTest.main(AutoCloseableTest.java:15) Suppressed: java.lang.RuntimeException: Exception in close() at AutoCloseableResource.close(AutoCloseableResource.java:16) at AutoCloseableTest.main(AutoCloseableTest.java:16)
The output clearly proves that close()
was indeed called BEFORE entering the catch
block that should handle the
exception. Yet, the Java developer discovering Java SE 7 might be surprised to see the exception stack trace line prefixed by
"Suppressed: ...
". It matches the exception thrown by the close()
method, but you could never encounter
such a form of stack trace prior to Java SE 7.
Suppressed Exceptions
If both the (explicit) try
block and the (implicit) resource handling code throw an exception, then the try
block
exception is the one which will be thrown. The resource handling exception will be made available via the Throwable.getSupressed()
method of the thrown exception. The Throwable[] Throwable.getSupressed()
is a new method added to the Throwable
class since Java SE 7 specifically for this purpose. If there were no suppressed exceptions then this will return an empty array.
The Java SE 7 extensions to java.lang.Throwable
are as follows:
public final void addSuppressed(Throwable exception)
- appends a suppressed exception to another one, so
as to avoid exception masking.
public final Throwable[] getSuppressed()
- gets the suppressed exceptions that were added to an exception.
These extensions were introduced especially for supporting the try-with-resources statement and fixing exception-masking problems.
An exception can be thrown from the block of code associated with the try-with-resources statement. In the example copyFile
above,
an exception can be thrown from the try
block, and up to two exceptions can be thrown from the try-with-resources
statement when it tries to close the BufferedReader
and BufferedWriter
objects. If an exception is thrown from
the try
block and one or more exceptions are thrown from the try-with-resources statement, then those exceptions thrown
from the try-with-resources statement are SUPPRESSED, and the exception thrown by the try
block is the one that is thrown by
the copyFile
method. You can retrieve these suppressed exceptions by calling the Throwable.getSuppressed
method
from the exception thrown by the try
block.
![]() ![]() ![]() |