Will this release my resources after being used?
InputStream inputStream;
try (InputStream unverifiedStream = connection.getInputStream()){
inputStream = unverifiedStream;
} catch (Exception e) {
e.printStackTrace();
}
//and use stream here to do other stuff with other streams
That will release your resources (close the stream) and leave you talking to a closed stream.
The assignment to inputStream does not copy the stream object. It copies the reference to the stream object. You now have two different ways to talk to the same object.
Since you are using a try-with-resource statement, and if by "released" you mean "closed" then yes.
Any instance implementing AutoCloseable opened in a try-with-resources statement is .close()d right before catch, so in your case unverifiedStream will be closed before you catch Exception.
It should also be noted that Closeable extends AutoCloseable, so all existing classes implementing Closeable will "magically" work within a try-with-resources statement.
Sample code:
public final class AutoCloseableExample
{
private static final class Foo
implements AutoCloseable
{
#Override
public void close()
throws IOException
{
System.out.println("foo");
throw new IOException();
}
}
public static void main(final String... args)
{
try (
final Foo foo = new Foo();
) {
System.out.println("try block");
} catch (IOException ignored) {
System.out.println("exception!");
} finally {
System.out.println("finally block");
}
}
}
Output:
try block
foo
exception!
finally block
Side note: you should not catch Exception since this also catches all unchecked exceptions (ie, RuntimeException and derivates). Catch more specific exceptions instead.
I haven't tried this, but I don't think it will compile if you try to use inputStream after the try-catch block, because inputStream won't be initialized if connection.getInputStream() throws an exception. Your catch block should assign a value or introduce a different flow of control to take care of that possibility.
If the try block completes normally, inputStream will refer to a closed stream outside the try-catch block, and most implementations will throw an exception on any operation you attempt on the stream.
Related
I have a Closeable that needs to clean up multiple resources in the close() method. Each resource is a final class that I cannot modify. None of the included resources are Closeable or AutoCloseable. I also need to call super.close(). So it appears that I cannot handle any of the resources* using try-with-resources. My current implementation looks something like this:
public void close() throws IOException {
try {
super.close();
} finally {
try {
container.shutdown();
} catch (final ShutdownException e) {
throw new IOException("ShutdownException: ", e);
} finally {
try {
client.closeConnection();
} catch (final ConnectionException e) {
throw new IOException("Handling ConnectionException: ", e);
}
}
}
}
I'd prefer a solution with less crazy nesting but I can't figure out how to take advantage of try-with-resources or any other features to do that. Code sandwiches don't seem to help here since I'm not using the resources at all, just cleaning them up. Since the resources aren't Closeable, it's unclear how I could use the recommended solutions in Java io ugly try-finally block.
* Even though the super class is Closeable, I cannot use super in a try-with-resources because super is just syntactic sugar and not a real Java Object.
This a good (albeit unorthodox) case for try-with-resources. First, you'll need to create some interfaces:
interface ContainerCleanup extends AutoCloseable {
#Override
void close() throws ShutdownException;
}
interface ClientCleanup extends AutoCloseable {
#Override
void close() throws ConnectionException;
}
If these interfaces are only used in the current class, I'd recommend making them inner interfaces. But they also work as public utility interfaces if you use them in multiple classes.
Then in your close() method you can do:
public void close() throws IOException {
final Closeable ioCleanup = new Closeable() {
#Override
public void close() throws IOException {
YourCloseable.super.close();
}
};
final ContainerCleanup containerCleanup = new ContainerCleanup() {
#Override
public void close() throws ShutdownException {
container.shutdown();
}
};
final ClientCleanup clientCleanup = new ClientCleanup() {
#Override
public void close() throws ConnectionException {
client.closeConnection();
}
};
// Resources are closed in the reverse order in which they are declared,
// so reverse the order of cleanup classes.
// For more details, see Java Langauge Specification 14.20.3 try-with-resources:
// https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.20.3
try (clientCleanup; containerCleanup; ioCleanup) {
// try-with-resources only used to ensure that all resources are cleaned up.
} catch (final ShutdownException e) {
throw new IOException("Handling ShutdownException: ", e);
} catch (final ConnectionException e) {
throw new IOException("Handling ConnectionException: ", e);
}
}
Of course this becomes even more elegant and concise with Java 8 lambdas:
public void close() throws IOException {
final Closeable ioCleanup = () -> super.close();
final ContainerCleanup containerCleanup = () -> container.shutdown();
final ClientCleanup clientCleanup = () -> client.closeConnection();
// Resources are closed in the reverse order in which they are declared,
// so reverse the order of cleanup classes.
// For more details, see Java Langauge Specification 14.20.3 try-with-resources:
// https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.20.3
try (clientCleanup; containerCleanup; ioCleanup) {
// try-with-resources only used to ensure that all resources are cleaned up.
} catch (final ShutdownException e) {
throw new IOException("Handling ShutdownException: ", e);
} catch (final ConnectionException e) {
throw new IOException("Handling ConnectionException: ", e);
}
}
This removes all the crazy nesting and it has the added benefit of saving the suppressed exceptions. In your case, if client.closeConnection() throws, we'll never know if the previous methods threw any exceptions. So the stacktrace will look something like this:
Exception in thread "main" java.io.IOException: Handling ConnectionException:
at Main$YourCloseable.close(Main.java:69)
at Main.main(Main.java:22)
Caused by: Main$ConnectionException: Failed to close connection.
at Main$Client.closeConnection(Main.java:102)
at Main$YourCloseable.close(Main.java:67)
... 1 more
By using try-with-resources, the Java compiler generates code to handle the suppressed exceptions, so we'll see them in the stacktrace and we can even handle them in the calling code if we want to:
Exception in thread "main" java.io.IOException: Failed to close super.
at Main$SuperCloseable.close(Main.java:104)
at Main$YourCloseable.access$001(Main.java:35)
at Main$YourCloseable $1.close(Main.java:49)
at Main$YourCloseable.close(Main.java:68)
at Main.main(Main.java:22)
Suppressed: Main$ShutdownException: Failed to shut down container.
at Main$Container.shutdown(Main.java:140)
at Main$YourCloseable$2.close(Main.java:55)
at Main$YourCloseable.close(Main.java:66)
... 1 more
Suppressed: Main$ConnectionException: Failed to close connection.
at Main$Client.closeConnection(Main.java:119)
at Main$YourCloseable$3.close(Main.java:61)
at Main$YourCloseable.close(Main.java:66)
... 1 more
Caveats
If the order of clean up matters, you need to declare your resource cleanup classes/lambdas in the reverse order that you want them run. I recommend adding a comment to that effect (like the one I provided).
If any exceptions are suppressed, the catch block for that exception will not execute. In those cases, it's probably better change the lambdas to handle the exception:
final Closeable containerCleanup = () -> {
try {
container.shutdown();
} catch (final ShutdownException e) {
// Handle shutdown exception
throw new IOException("Handling shutdown exception:", e);
}
}
Handling the exceptions inside the lambda does start to add some nesting, but the nesting isn't recursive like the original so it'll only ever be one level deep.
Even with those caveats, I believe the pros greatly outweigh the cons here with the automatic suppressed exception handling, conciseness, elegance, readability, and reduced nesting (especially if you have 3 or more resources to clean up).
I have a sample code here. Will the FileInputStream created by the function, get automatically closed when the code exists the try/catch block of parentFunction ?
Or does it need to be explicitly closed in the someOtherFunction() itself ?
private void parentFunction() {
try {
someOtherFunction();
} catch (Exception ex) {
// do something here
}
}
private void someOtherFunction() {
FileInputStream stream = new FileInputStream(currentFile.toFile());
// do something with the stream.
// return, without closing the stream here
return ;
}
You have to use the resource with try-with-resource block.
Please read docs for AutoCloseable interface: https://docs.oracle.com/javase/8/docs/api/java/lang/AutoCloseable.html
method of an AutoCloseable object is called automatically when exiting a try-with-resources block for which the object has been declared in the resource specification header.
It needs to either be explicitly closed in the someOtherFunction() method, or used in a try-with-resources block:
private void someOtherFunction() {
try (FileInputStream stream = new FileInputStream(currentFile.toFile())) {
// do something with the stream.
} // the stream is auto-closed
}
I have some junit tests which create some resources which should also be closed.
One way to implement this logic is using the #Before and #After approach.
What I did was to encapsulate the creation in some utility class to be reused. For example:
class UserCreatorTestUtil implements AutoClosable {
User create() {...}
void close() {...}
}
The whole point is for the object to close itself, rather than needing to remember to close it in #After.
The usage should be:
#Test
void test() {
try (UserCreatorTestUtil userCreatorTestUtil = new UserCreatorTestUtil()) {
User user = userCreatorTestUtil.create();
// Do some stuff regarding the user's phone
Assert.assertEquals("123456789", user.getPhone());
}
}
The problem is that junit's assert keyword throws an Error - not Exception.
Will the try-with-resource "catch" the Error and invoke the close method?
* Couldn't find the answer in the try-with-resources documentation.
It does not catch anything. But it does finally close all resources.
finally blocks are run even when an Error is thrown.
The pseudo-code of a basic try-with-resources statement is (cf Java Language Specification ยง14.20.3.1):
final VariableModifiers_minus_final R Identifier = Expression;
Throwable #primaryExc = null;
try ResourceSpecification_tail
Block
catch (Throwable #t) {
#primaryExc = #t;
throw #t;
} finally {
if (Identifier != null) {
if (#primaryExc != null) {
try {
Identifier.close();
} catch (Throwable #suppressedExc) {
#primaryExc.addSuppressed(#suppressedExc);
}
} else {
Identifier.close();
}
}
}
As you can see it catches Throwable not Exception which includes Error but only to get the primary exception in order to add as suppressed exceptions any exceptions that occurred while closing the resources.
You can also notice that your resources are closed in the finally block which means that they will be closed whatever happens (except in case of a System.exit of course as it terminates the currently running Java Virtual Machine) even in case an Error or any sub class of Throwable is thrown.
Try-with-resources don't catch anything in and of themselves.
However, you can attach a catch block to the end of the try-with-resources block, to catch whatever types of Throwable you like:
try (UserCreatorTestUtil userCreatorTestUtil = new UserCreatorTestUtil()) {
// ... Whatever
} catch (RuntimeException e) {
// Handle e.
} catch (Exception | Throwable t) {
// Handle t.
}
The idea behind try-with-resources is to make sure that the resources should be closed.
The problem with conventional try-catch-finally statements is that let's suppose your try block throws an exception; now usually you'll handle that exception in finally block.
Now suppose an exception occurs in finally block as well. In such a case, the exception thrown by try catch is lost and the exception generated in finally block gets propagated.
try {
// use something that's using resource
// e.g., streams
} catch(IOException e) {
// handle
} finally {
stream.close();
//if any exception occurs in the above line, than that exception
//will be propagated and the original exception that occurred
//in try block is lost.
}
In try-with-resources the close() method of the resource will get automatically called, and if the close() throws any exception, the rest of the finally isn't reached, and the original exception is lost.
Contrast that with this:
try (InputStream inputStream= new FileInputStream("C://test.txt")){
// ... use stream
} catch(IOException e) {
// handle exception
}
in the above code snippet, the close() method automatically gets called and if that close() method also generated any exception, than that exception will automatically get suppressed.
See also: Java Language Specification 14.20.3
Misconception on your end: try-with-resources does not do a catch.
It does a final finally, therefore the kind of "problem" doesn't matter.
See the JLS for further information!
The finally block is mainly used to prevent resource leaks which can be achieved in close() method of resource class. What's the use of finally block with try-with-resources statement, e.g:
class MultipleResources {
class Lamb implements AutoCloseable {
public void close() throws Exception {
System.out.print("l");
}
}
class Goat implements AutoCloseable {
public void close() throws Exception {
System.out.print("g");
}
}
public static void main(String[] args) throws Exception {
new MultipleResources().run();
}
public void run() throws Exception {
try (Lamb l = new Lamb(); Goat g = new Goat();) {
System.out.print("2");
} finally {
System.out.print("f");
}
}
}
Ref: K.Seirra, B. Bates OCPJP Book
Just like in regular try-catch-finally block - finally block is used when you want something to always happen, no matter if operation in try block succeeds or not.
I think your question is about providing some use-case when it is really useful. Try to imagine a situation when you have to tell one collabolator (or publish an event) that your processing is finished - regardless of its result. You can then put in the finally block the code which is resposible for announcing the finishing of processing.
Plase note that when some operation in try-with-resources block without catch throws an exception, the code following that block will not be executed.
The code in finally block with always get executed unless the thread that executing the code or the JVM is terminated.
This ensures that any resources you allocated will get cleaned up in the finally regardless.
The Java doc has a detail explanation of finally.
I read that the catch block in try-with-resources is optional.
I've tried creating a Connection object in a try-with-resources block, with no subsequent catch block, only to get compiler error from eclipse:
"Unhandled exception type SQLException thrown by automatic close() invocation."
Since every resource that can be used in try-with-resources implements AutoCloseable, and so potentially throws an exception upon invocation of the close() method, I don't understand how the catch clause is optional, given that it's not allowing me to skip catching the exception from close().
Is there some special requirement that the specific implementation of AutoCloseable not directly declare any exception thrown in its close() method? (e.g. override AutoCloseable's close() throws Exception with a close() which does not throw any Exception)?
..or is this possibly just an eclipse issue?
Edit: Here's the simplest code fragment that still triggers the problem:
try (Connection con = dataSource.getConnection()) {
/*...*/
}
Thoughts on whether or not this is related to the use of a JNDI DataSource?
Thanks in advance.
It is optional if close() is not able to throw a checked exception. However, if close() can, then a checked exception would need to handled in a normal fashion, either with a catch block, or by throwing from the method that try-with-resources block is in.
More details are in JLS 14.2.3
14.20.3.2. Extended try-with-resources
A try-with-resources statement with at least one catch clause and/or a finally clause is called an extended try-with-resources statement.
The meaning of an extended try-with-resources statement:
try ResourceSpecification
Block
[Catches]
[Finally]
is given by the following translation to a basic try-with-resources statement nested inside a try-catch or try-finally or try-catch-finally statement:
try {
try ResourceSpecification
Block
}
[Catches]
[Finally]
The effect of the translation is to put the resource specification "inside" the try statement. This allows a catch clause of an extended try-with-resources statement to catch an exception due to the automatic initialization or closing of any resource.
Furthermore, all resources will have been closed (or attempted to be closed) by the time the finally block is executed, in keeping with the intent of the finally keyword.
Thoughts on whether or not this is related to the use of a JNDI DataSource?
Yes, it is.
In the example try-with-resourses block you've provided, it is necessary to catch the exception and handle, or throw from the method the block is in, because SQLException is a checked exception.
You could just be throwing the exception up (or catching it in another try-catch block):
private static void test() throws IOException {
try(InputStream is = new FileInputStream("test.txt")) {
while(is.read() > -1) {
}
} finally {
// Will get executed, even if exception occurs
System.out.println("Finished");
}
}
You can create an AutoClosable that does not require an explicit catch-block by declaring your AutoClosable's close() method without any Exception or with a RuntimeException. Without any Exception it is clear that no catch-block is required. Further, the compiler does not statically check for a RuntimeException to be catched (in contrast to checked Exceptions).
Example:
public class AutoClosableDemo
{
public static void main( final String[] args )
{
try (MyAutoCloseable1 mac1 = new MyAutoCloseable1())
{
System.out.println( "try-with-resource MyAutoCloseable1" );
}
try (MyAutoCloseable2 mac2 = new MyAutoCloseable2())
{
System.out.println( "try-with-resource MyAutoCloseable2" );
}
// The following is not allowed, because
// "Unhandled exception type Exception thrown by automatic close() invocation on mac3"
// try (MyAutoCloseable3 mac3 = new MyAutoCloseable3())
// {
// System.out.println( "try-with-resource MyAutoCloseable13" );
// }
System.out.println( "done" );
}
public static class MyAutoCloseable1 implements AutoCloseable
{
#Override
public void close()
{
System.out.println( "MyAutoCloseable1.close()" );
}
}
public static class MyAutoCloseable2 implements AutoCloseable
{
#Override
public void close() throws RuntimeException
{
System.out.println( "MyAutoCloseable2.close()" );
}
}
public static class MyAutoCloseable3 implements AutoCloseable
{
#Override
public void close() throws Exception
{
System.out.println( "MyAutoCloseable3.close()" );
}
}
}
You could check the JLS but there is actually a relatively easy reasoning why this is the only correct way the language should behave.
The main rule of checked exceptions is that any checked exception declared by a method must be handled, either by catching it or letting the calling method throw it.
The try-with-resources always (implicitly) calls the close method.
So if the specific close method of the AutoClosable you use (determined by the type declared in try) declares to throw a checked exception such as a SQLException you do need to handle this checked exception somewhere, otherwise it would be possible to violate the rule!
If the close method does not declare that it throws a checked exception, the rule is not violated and you do not need to handle a checked exception for implicitly calling the close method. It is actually a compilation failure if you do try to catch a checked exception that is never declared to be thrown.
Not every Java class (!) throws an exception. Sometimes you just want to use a try-with-resources to use the auto-close feature, and nothing else.
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally {
if (br != null) br.close();
}
This the catch is optional because readLine() doesn't throw a (checked) exception.
Yes, close() could throw an exception, but the try-with-resources handles that too.
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
So this try-with-resources doesn't need a catch.