JDK 1.7 introduced the "try-with-resources" statement [JLS 2011] §14.20.3, "try-with-resources" that makes it much easier to deal with resources that implement the java.lang.AutoCloseable
interface, including those that implement the java.io.Closeable
interface.
Using the try-with-resources statement avoids problems that can arise when closing resources with an ordinary try-catch-finally block, such as failing to close a resource because an exception is thrown as a result of closing another resource, or masking an important exception when a resource is closed.
Noncompliant Code Example
This noncompliant code example uses an ordinary try-finally block to try to close two resources. However, if closing the Bufferedreader
br
results in an exception being thrown, then the BufferedWriter
bw
will not be closed.
public void err54_nce1(String inPath, String outPath) throws IOException{ BufferedReader br = null; BufferedWriter bw = null; try { br = new BufferedReader(new FileReader(inPath)); bw = new BufferedWriter(new FileWriter(outPath)); // process the input and produce the output } finally { if (br != null) { br.close(); } if (bw != null) { bw.close(); } } }
Compliant Solution
This compliant solution uses a try-with-resources statement which will guarantee that both br
and bw
are closed, regardless of any exceptions potentially thrown during the close operations.
public void err54_cs1(String inPath, String outPath) throws IOException{ try (BufferedReader br = new BufferedReader(new FileReader(inPath)); BufferedWriter bw = new BufferedWriter(new FileWriter(outPath));) { // process the input and produce the output } }
Noncompliant Code Example
This noncompliant code example uses an ordinary try-finally block to try to close a resource. However, if there is an exception thrown during the processing of the input and another exception thrown when closing the Bufferedreader
br
, then the exception thrown as a result of processing the input will be lost, and important information about that exceptional circumstance may be missed.
public void err54_nce2(String inPath) throws IOException{ BufferedReader br = null; try { br = new BufferedReader(new FileReader(inPath)); // process the input and produce the output } finally { if (br != null) { br.close(); } } }
Compliant Solution
This compliant solution uses a try-with-resources statement which will not suppress any exceptions thrown during the processing of the input while still guaranteeing that br
is closed.
public void err54_cs2(String inPath) throws IOException{ try (BufferedReader br = new BufferedReader(new FileReader(inPath));) { // process the input and produce the output } catch (IOException ex) { System.err.println("thrown exception: " + ex.toString()); Throwable[] suppressed = ex.getSuppressed(); for (int i = 0; i < suppressed.length; i++) { System.err.println("suppressed exception: " + suppressed[i].toString()); } } }
If only one exception is thrown, either during opening, processing, or closing of the file, it will be printed by the "thrown exception: "
statement. If an exception is thrown during processing, and another one is thrown while trying to close the file, then the "thrown exception: "
statement will print the exception encountered while closing the file, and the "suppressed exception: "
statement will print the exception encountered during processing.
Applicability
Failing to use a try-with-resources statement when dealing with closeable resources may result in some resources not being closed, or important exceptions being masked, possibly resulting in a denial of service attack.