The try-with-resources statement automatically closes all the resources at the end of the statement. A resource is an object to be closed at the end of the program.
Its syntax is:
try (resource declaration) {
// use of the resource
} catch (ExceptionType e1) {
// catch block
}
As seen from the above syntax, we declare the try-with-resources statement by,
- declaring and instantiating the resource within the
tryclause. - specifying and handling all exceptions that might be thrown while closing the resource.
Note: The try-with-resources statement closes all the resources that implement the AutoCloseable interface.
Let us take an example that implements the try-with-resources statement.
Example 1: try-with-resources
import java.io.*;
class Main {
public static void main(String[] args) {
String line;
try(BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {
while ((line = br.readLine()) != null) {
System.out.println("Line =>"+line);
}
} catch (IOException e) {
System.out.println("IOException in try block =>" + e.getMessage());
}
}
}
Output if the test.txt file is not found.
IOException in try-with-resources block =>test.txt (No such file or directory)
Output if the test.txt file is found.
Entering try-with-resources block Line =>test line
In this example, we use an instance of BufferedReader to read data from the test.txt file.
Declaring and instantiating the BufferedReader inside the try-with-resources statement ensures that its instance is closed regardless of whether the try statement completes normally or throws an exception.
If an exception occurs, it can be handled using the exception handling blocks or the throws keyword.
Suppressed Exceptions
In the above example, exceptions can be thrown from the try-with-resources statement when:
- The file
test.txtis not found. - Closing the
BufferedReaderobject.
An exception can also be thrown from the try block as a file read can fail for many reasons at any time.
If exceptions are thrown from both the try block and the try-with-resources statement, exception from the try block is thrown and exception from the try-with-resources statement is suppressed.
Retrieving Suppressed Exceptions
In Java 7 and later, the suppressed exceptions can be retrieved by calling the Throwable.getSuppressed() method from the exception thrown by the try block.
This method returns an array of all suppressed exceptions. We get the suppressed exceptions in the catch block.
catch(IOException e) {
System.out.println("Thrown exception=>" + e.getMessage());
Throwable[] suppressedExceptions = e.getSuppressed();
for (int i=0; i<suppressedExceptions.length; i++) {
System.out.println("Suppressed exception=>" + suppressedExceptions[i]);
}
}
Advantages of using try-with-resources
Here are the advantages of using try-with-resources:
1. finally block not required to close the resource
Before Java 7 introduced this feature, we had to use the finally block to ensure that the resource is closed to avoid resource leaks.
Here's a program that is similar to Example 1. However, in this program, we have used finally block to close resources.
Example 2: Close resource using finally block
import java.io.*;
class Main {
public static void main(String[] args) {
BufferedReader br = null;
String line;
try {
System.out.println("Entering try block");
br = new BufferedReader(new FileReader("test.txt"));
while ((line = br.readLine()) != null) {
System.out.println("Line =>"+line);
}
} catch (IOException e) {
System.out.println("IOException in try block =>" + e.getMessage());
} finally {
System.out.println("Entering finally block");
try {
if (br != null) {
br.close();
}
} catch (IOException e) {
System.out.println("IOException in finally block =>"+e.getMessage());
}
}
}
}
Output
Entering try block Line =>line from test.txt file Entering finally block
As we can see from the above example, the use of finally block to clean up resources makes the code more complex.
Notice the try...catch block in the finally block as well? This is because an IOException can also occur while closing the BufferedReader instance inside this finally block so it is also caught and handled.
The try-with-resources statement does automatic resource management. We need not explicitly close the resources as JVM automatically closes them. This makes the code more readable and easier to write.
2. try-with-resources with multiple resources
We can declare more than one resource in the try-with-resources statement by separating them with a semicolon ;
Example 3: try with multiple resources
import java.io.*;
import java.util.*;
class Main {
public static void main(String[] args) throws IOException{
try (Scanner scanner = new Scanner(new File("testRead.txt"));
PrintWriter writer = new PrintWriter(new File("testWrite.txt"))) {
while (scanner.hasNext()) {
writer.print(scanner.nextLine());
}
}
}
}
If this program executes without generating any exceptions, Scanner object reads a line from the testRead.txt file and writes it in a new testWrite.txt file.
When multiple declarations are made, the try-with-resources statement closes these resources in reverse order. In this example, the PrintWriter object is closed first and then the Scanner object is closed.
Java 9 try-with-resources enhancement
In Java 7, there is a restriction to the try-with-resources statement. The resource needs to be declared locally within its block.
try (Scanner scanner = new Scanner(new File("testRead.txt"))) {
// code
}
If we declared the resource outside the block in Java 7, it would have generated an error message.
Scanner scanner = new Scanner(new File("testRead.txt"));
try (scanner) {
// code
}
To deal with this error, Java 9 improved the try-with-resources statement so that the reference of the resource can be used even if it is not declared locally. The above code will now execute without any compilation error.