Exception Handling – The try-with-resources statement

Generally finally block is used to close all the resources (viz., file, database connection, socket or anything that should be closed after its task is done) to prevent any leaks.

Sample code:

public class ResourceMgt {
	public static void main(String[] args) {
		BufferedReader br = null;
		try {
			br = new BufferedReader(new FileReader("C://test.txt"));
			System.out.println(br.readLine());
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (br != null)
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		} //finally
	} // main
}

If you look at the above sample code, to close the BufferedReader resource, we had to check if it is still open and then invoke the close() method. There is a possibility of the close method throwing an exception and hence it has to be surrounded in a try catch block. This code is to be repeated for every resource that is opened. For big applications, you will see a lot of duplicate code due to this.

In Java 7 and later, the try-with-resources statement makes sure that every opened resource is closed at the end of the statement. So a try-with-resources statement is nothing but a try statement that declares one or more resources. A resource is said to be any object that implements java.lang.AutoCloseable interface. This interface, in turn, includes all objects that implement java.io.Closeable interface.

So the same example using a try-with-resources statement can be written as,

public class ResourceMgt {
	public static void main(String[] args) {
		try(BufferedReader br = new BufferedReader(new FileReader("C://test.txt"))){
			System.out.println(br.readLine());
		} catch (IOException e) {
			e.printStackTrace();
		} 
	} // main
}

A parenthesis is introduced immediately after the try keyword and all resources should be declared within the parenthesis only. These resources are separated with semicolons.

As you can see, the code using try-with-resources statement,

  • Is readable with reduced number of lines.
  • Code looks very neat.
  • Finally block is not required if its sole purpose is just to close the resources.
  • Automatic resource management.

In our example, since the BufferedReader instance is declared in a try-with-resource statement, it will be closed regardless of whether the try statement completes successfully or not (as the method readLine() can throw an IOException).

Points worthy to note:

  • The try-with-resources statement is just like an ordinary try statement. It can have catch and finally blocks as usual.
  • It is important to remember that the declared resources are closed before catch and finally blocks are run.
  • To declare multiple resources in the same try statement, the resources have to be separated with

Example,

try(BufferedReader br = new BufferedReader(new FileReader("C://test.txt")); 
       ZipFile zf = new ZipFile("test1.zip")){…}
  • Once the try-with-resources block completes (either successfully or by throwing an exception), the close methods of those resources will be invoked automatically in reverse order.

Considering the above example,

the close() methods of ZipFile and BufferedWriter will be called in the mentioned order (i.e. reverse order) to avoid any dependency problems that might arise.

  • If there is any issue while initializing any of the resources, then all the resources that are initialized thus far will be closed in reverse order.
  • To use custom classes as resources, it is necessary for those classes to implement the lang.AutoCloseable or java.io.Closeable interfaces.
  • The close() methods of Closeable and AutoCloseable interfaces throw exceptions of type IOException and Exception respectively.
  • Since 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, it is better to use AutoCloseable for customization.

Custom Implementation of AutoCloseable Interface:

The AutoCloseable interface is pretty easy to implement as it just has a single method, close().

public interface AutoClosable {
    public void close() throws Exception;
}

Let us create two custom classes that implement AutoCloseable interface,

Bar.java

public class Bar implements AutoCloseable{

	public Bar(){
		System.out.println("Inside Bar Class");
	}
	public void doSomething(){
		System.out.println("Doing something in Bar!");
	}
	public void close() throws Exception{
		System.out.println("Closed Bar");
	}
}

Foo.java

public class Foo implements AutoCloseable{

	public Foo(){
		System.out.println("Inside Foo Class");
	}
	public void doSomething() throws Exception{
		throw new Exception("Exception from Foo doSomething() method");
	}
	public void close() throws Exception{
		System.out.println("Closing Foo");
		throw new Exception("Unable to close Foo...");
	}
}

The doSomething() and close() methods of Foo class throw an exception.

MyTryWithResources.java

public class MyTryWithResources {
	
	public static void main(String[] args){
		try(Bar b = new Bar(); Foo f = new Foo()){
			b.doSomething();
			f.doSomething();
		}catch(Exception ex){
			System.out.println("In catch... " + ex);
		}finally{
			System.out.println("In finally...");
		}
	}
}

Output:

try with resources output

Explanation:

  1. The first thing to notice here is that the order in which the resources are opened and closed. Bar is opened and then Foo but while closing, reverse order is followed. Foo is closed and then Bar resource.
  2. Foo’s close() throws an exception but if you notice the generated output, it is suppressed. Only the exception that is generated in the try block by doSomething() is thrown by the main method of MyTryWithResources

This is the main concept to understand here in try-with-resources. Let us try to distil this information step by step,

  • Bar and Foo resources are created in the try-with-resources block.
  • Try block starts to execute.
  • The doSomething() of Bar class gets executed successfully and prints the message, “Doing something in Bar!” to console.
  • An exception is thrown from the doSomething() method of the Foo class.
  • Before transferring the control to catch method to handle the exception, resources are closed by invoking their respective close() methods.
  • The close() of Foo class prints the message, “Closing Foo” to console and throws an exception which gets suppressed as the exception thrown by the try block gets exposed.
  • This suppression of exception from try-with-resources statement happens only when both try block and try-with-resources statement (close() method) throw exceptions.
  • The close() of Bar class is run and it prints the message “Closing Bar” to the console.
  • Then finally block gets executed.
  1. What if you want to retrieve the suppressed exceptions as well? Not to worry. In Java SE 7 and later, they can be retrieved by using getSuppressed() method.
  2. Though an exception is thrown while closing a particular resource, all opened resources will be closed irrespective of the thrown exception. In our example, though there was an exception while closing Foo resources, Bar resource was closed successfully as well.

In order to get the suppressed exceptions, just add the line, exception_handler_reference_variable.getSuppressed() to the catch block of the MyTryWithResources class as shown below,

catch(Exception ex){
			System.out.println("No. of suppressed exceptions: " + ex.getSuppressed().length);
			System.out.println("In catch... " + ex);
		}

Output:

Inside Bar Class
Inside Foo Class
Doing something in Bar!
Closing Foo
Closed Bar
No. of suppressed exceptions: 1
In catch... java.lang.Exception: Exception from Foo doSomething() method
In finally...

By following these examples, it should not be that difficult to wrap your heads around this concept. Have a nice day!

Series Navigation<< Exception Handling – try/catch/finally blocks
By | 2017-06-20T07:16:58+00:00 June 20th, 2017|Core Java|0 Comments

About the Author:

Leave A Comment