Search This Blog

Wednesday 6 January 2016

try with resource

I have often used the try-with-resources Statement that was introduced in Java 7. Today I decided to look a little deep into it.
In earlier versions of java when dealing with resources that need closing, the code something like below:

public static void main(String[] args) {
      BufferedWriter bufferedWriter = null;
      try {
         bufferedWriter = new BufferedWriter(new FileWriter(new File("")));
      } catch (IOException exception) {
         // handle failure in performing the operation
      } finally {
         try {
            if (bufferedWriter != null) {
               bufferedWriter.close();
            }
         } catch (IOException e) {
            // Failure in closing the resource
         }
      }
   }
In the above code we created an instance of BufferedWriter and attempted to write to the file. Once the operation completes, we need to close the resource. Why close - to ensure any system resources allocated are released. With the new Java 7 feature, this code changes to something far simpler:
public static void main(String[] args) {

      try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(new File("")))) {
         // do all operations here
      } catch (IOException exception) {
         // handle failure in performing the operation
      }
   }
Here the try statement now also includes the creation of the resource. Hence the name "try with resource". But what about closing the resource ? With Java 7 we have a new interface
public interface AutoCloseable {
    void close() throws Exception;
}
Here once the try block completes the close method for the resource is executed thus closing the resource. In case of some failure the system will throw out an exception. To look at the implementation for the BufferedWriter class for instance:
@SuppressWarnings("try")
    public void close() throws IOException {
        synchronized (lock) {
            if (out == null) {
                return;
            }
            try (Writer w = out) {
                flushBuffer();
            } finally {
                out = null;
                cb = null;
            }
        }
    }
Here the code throws an IOException - makes sense, the subclass should throw the specific exception when something goes wrong and not the generic Exception instance. In fact they dont even need to throw an exception.
I decided to create a Resource class of my own:
public class OperationLogger implements AutoCloseable {

   private String name;

   public OperationLogger(String name) {
      this.name = name;
   }

   public void start() {
      System.out.println("Operation " + name + " has been started");
   }

   @Override
   public void close() throws Exception {
      System.out.println("Operation " + name + " has been closed");
   }

}
The class does nothing but log messages to console. I used it here
public static void main(String[] args) {
      try (OperationLogger operationLogger = new OperationLogger("Testing")) {
         operationLogger.start();
//         throw new RuntimeException();
         // do all operations here
         System.out.println("Try completed");
      } catch (Exception exception) {
         exception.printStackTrace();
         // handle failure in performing the operation
         System.out.println("Catch completed");
      }
   }
The output on running this code:
Operation Testing has been started
Try completed
Operation Testing has been closed
As seen here, once the try block completed the resource was close. If I were to uncomment the line in code that throws an exception then the output is:
Operation Testing has been started
Operation Testing has been closed
java.lang.RuntimeException
 at TryResourceExample.main(TryResourceExample.java:37)
Catch completed
Here too, once the control exited the try block, the resource was closed before the control was transferred to the catch block. What if I introduce a finally block ?
public static void main(String[] args) {
      try (OperationLogger operationLogger = new OperationLogger("Testing")) {
         operationLogger.start();
//         throw new RuntimeException();
         // do all operations here
         System.out.println("Try completed");
      } catch (Exception exception) {
         exception.printStackTrace();
         // handle failure in performing the operation
         System.out.println("Catch completed");
      } finally {
         System.out.println("Finally completed");
      }
   }
The output is:
Operation Testing has been started
Try completed
Operation Testing has been closed
Finally completed
The finally executes in the last. Sequence is : try -> close resource -> finally.
There is another interface called Closeable
public interface Closeable extends AutoCloseable {
    public void close() throws IOException;
}
Interestingly this is a java 5 interface which has been made to extend the new Java 7 AutoCloseable interface. Only difference between the two is that this one throws an IoException making it inherently more suitable for our IO rekated Resource classes.

No comments:

Post a Comment