2
votes

During a code review I found the following code snippet:

try (
   Connection con = new SqlSessionFactoryBuilder()
    .build(configuration)
    .buildFactory()
    .openSession()
    .getConnection()
){
   // do stuff here with 'con' and not close anything   
}

Session, Connection, SqlSessionFactory are iBatis implementations, but the questions is interested in any 'stacked' implementation of the Closable interface.

I am assuming 'try with resources' closes the resource, that is instantiated - con in this case. Normally you'd close session and connection each individually. If using the above code the close() method will just be called on con object, so session is not explicitly called and will rely on the garbage collection?

Will the code be any better using:

try (
   Session session = new SqlSessionFactoryBuilder()
    .build(configuration)
    .buildFactory()
    .openSession(); 
   Connection con = session.getConnection();
){
   // do stuff here with 'con' and not close anything
}

The latter approach seems cleaner in my eyes as it should call close() correctly. Or is my interpretation wrong and just boilerplate code?

1
This might be a better question for codereview than for StackOverflow. For my part, I think your idea is correct, and this is probably something you should call out and change in the code review - this try syntax is allowed for precisely this reason, after all.Green Cloak Guy
I think it's suited here ok as it's more a language feature or language mechanics question than code polishing. Thanks for your comment!supernova

1 Answers

3
votes

Your interpretation is correct, try-with-resources will close only resources explicitly declared in resources block.

However, in most cases the first approach will work as well. That is because usually when some Closeable uses another Closeable, it will try to close it inside of its close() method. This mechanism doesn't have anything to do with the garbage collector tho (which would just remove an object without releasing the resource).

Other than the situation where a Closeable wouldn't close its resources, there could be other sources of resources leak in the first approach as well. Consider a following case:

try(BufferedInputStream bufferedInput = new BufferedInputStream(
                                            new FileInputStream("file.txt"))
)

In this example, FileInputStream will be created first. Just then it will be passed into a contructor of BufferedInputStream. What would happen when an exception occurs during creation of BufferedInputStream? FileInputStream won't ever be closed. On the other hand, when you declare those as two separate resources like so:

try(FileInputStream input = new FileInputStream("file.txt");
    BufferedInputStream bufferedInput = new BufferedInputStream(input)
)

Java itself will make sure that both of the resources will be closed. The following is stated in JSL - 14.20.3.1. Basic try-with-resources :

In a basic try-with-resources statement that manages multiple resources:

If the initialization of a resource completes abruptly because of a throw of a value V, then:

If the automatic closings of all successfully initialized resources (possibly zero) complete normally, then the try-with-resources statement completes abruptly because of a throw of the value V.

There are probably more cases that might cause resource leak as well.