Try-with-resources in Java - Quiz
Total: 6 questions
1. What is try-with-resources in Java, and why is it better than closing a resource in a finally block?
What is try-with-resources in Java, and why is it better than closing a resource in a finally block?
Try-with-resources is a form of the try statement (Java 7) in which resources are declared in parentheses after try and closed automatically: close() is called when the try block exits, both on normal completion and when an exception is thrown. A resource is any object whose class implements AutoCloseable.
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
Compared with try-finally: you do not write the close() call yourself; several resources go into one pair of parentheses instead of nested try-finally blocks; and, most importantly, an exception from close() does not overwrite the original one. With try-finally, if both readLine() and close() fail, only the exception from close() leaves the method and the real cause is lost. With try-with-resources the exception from the try block is propagated, and the one from close() is attached to it as suppressed.
2. How do you declare several resources in try-with-resources, and in what order are they closed?
How do you declare several resources in try-with-resources, and in what order are they closed?
Resources are listed in one pair of parentheses, separated by semicolons. They are opened left to right and closed in reverse order: the last one opened is closed first.
try (FileReader fr = new FileReader(path);
BufferedReader br = new BufferedReader(fr)) {
return br.readLine();
} // br is closed first, then fr
If the constructor of the second resource throws, the first resource that is already open is still closed. That is why wrapper streams are better declared as separate resources: in new ObjectInputStream(new FileInputStream(f)) the inner FileInputStream is not a resource and stays open if the ObjectInputStream constructor throws StreamCorruptedException. Closing twice (BufferedReader.close() has already closed the FileReader) is safe: for a Closeable a repeated close() call must have no effect.
3. What is the difference between AutoCloseable and Closeable, and what can be a resource in try-with-resources?
What is the difference between AutoCloseable and Closeable, and what can be a resource in try-with-resources?
A resource can only be an object whose class implements java.lang.AutoCloseable: I/O streams, sockets, JDBC connections, Scanner, your own classes.
AutoCloseable— packagejava.lang, Java 7, methodvoid close() throws Exception; a repeatedclose()call may have side effects (idempotence is recommended, not required).Closeable— packagejava.io, Java 5, extendsAutoCloseablesince Java 7; methodvoid close() throws IOException; a repeatedclose()call must do nothing (idempotence).
Because Closeable extends AutoCloseable, every stream from java.io qualifies automatically. In your own resource, narrow the exception of close(): declare throws IOException or no checked exceptions at all, so that callers do not have to catch a generic Exception.
4. What are suppressed exceptions in try-with-resources, and how do you get them with getSuppressed()?
What are suppressed exceptions in try-with-resources, and how do you get them with getSuppressed()?
If an exception is thrown in the try block and then close() throws too, the exception from the try block is propagated, and the one from close() is attached to it via addSuppressed(). It is not lost: Throwable.getSuppressed() returns a Throwable[] array with the suppressed exceptions.
try (FaultyResource r = new FaultyResource()) { // close() throws IllegalStateException
throw new RuntimeException("try failed");
} catch (RuntimeException e) {
System.out.println(e.getMessage()); // try failed
for (Throwable s : e.getSuppressed()) {
System.out.println(s.getMessage()); // message from close()
}
}
In equivalent try-finally code the exception from close() would be propagated instead, and getSuppressed().length would be 0. Suppressed exceptions are not logged separately, but e.printStackTrace() and most loggers print them inside the stack trace of the main exception as a Suppressed: ... line.
5. In what order do close(), catch and finally run in try-with-resources?
In what order do close(), catch and finally run in try-with-resources?
First all resources are closed (in reverse order of declaration), then catch runs, and finally runs last.
try (Resource r = new Resource("R")) { // prints "open R" / "close R"
throw new IllegalArgumentException("fail");
} catch (IllegalArgumentException e) {
System.out.println("catch: " + e.getMessage());
} finally {
System.out.println("finally");
}
// open R
// close R
// catch: fail
// finally
Consequences: in catch and finally the resource is already closed and out of scope, and an exception thrown while closing can also be caught by that catch. If the exception is thrown while the resource is being created (for example, FileNotFoundException in the FileReader constructor), the try body does not run, there is nothing to close, and control goes straight to the matching catch.
6. What changed in try-with-resources in Java 9?
What changed in try-with-resources in Java 9?
Since Java 9 you can put an existing variable in the try-with-resources parentheses, as long as it is final or effectively final (nothing is assigned to it after initialisation). In Java 7 and 8 the resource had to be declared inside the parentheses, even if the object already existed.
// Java 7/8
try (BufferedReader br = reader) {
return br.readLine();
}
// Java 9+
try (reader) {
return reader.readLine();
}
If the variable is reassigned anywhere in the method, try (reader) does not compile: the variable is no longer effectively final.