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:
I decided to create a Resource class of my own:
There is another interface called Closeable
In earlier versions of java when dealing with resources that need closing, the code something like below:
publicstatic void main(String[] args) {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:
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
}
}
}
publicstatic void main(String[] args) {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
try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(new File("")))) {
// do all operations here
} catch (IOException exception) {
// handle failure in performing the operation
}
}
publicinterface AutoCloseable {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:
void close() throws Exception;
}
@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:
publicclass OperationLogger implements AutoCloseable {The class does nothing but log messages to console. I used it here
privateString name;
public OperationLogger(String name) {
this.name = name;
}
publicvoid start() {
System.out.println("Operation " + name + " has been started");
}
@Override
publicvoid close() throws Exception {
System.out.println("Operation " + name + " has been closed");
}
}
publicstatic void main(String[] args) {The output on running this code:
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");
}
}
Operation Testing has been startedAs 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:
Try completed
Operation Testing has been closed
Operation Testing has been startedHere 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 ?
Operation Testing has been closed
java.lang.RuntimeException
at TryResourceExample.main(TryResourceExample.java:37)
Catch completed
publicstatic void main(String[] args) {The output is:
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");
}
}
Operation Testing has been startedThe finally executes in the last. Sequence is : try -> close resource -> finally.
Try completed
Operation Testing has been closed
Finally completed
There is another interface called Closeable
publicinterface Closeable extends AutoCloseable {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.
publicvoid close() throwsIOException;
}