Why is try-with-resources catch block selectively optional?

22,685

Solution 1

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.

Solution 2

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");
    }
}
Share:
22,685
Mer
Author by

Mer

I use this site for reference often. I'm an experienced programmer, but a complete beginner relative to most of the contributors here. ...

Updated on July 06, 2020

Comments

  • Mer
    Mer almost 4 years

    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.

  • Edwin Dalorzo
    Edwin Dalorzo over 9 years
    I don't get it. This example does not use try-with-resources.
  • markspace
    markspace over 9 years
    I showed the code that try-with-resources replaces. It doesn't have a catch either, which is why try-with-resources had to make the catch optional.
  • Edwin Dalorzo
    Edwin Dalorzo over 9 years
    The place where you create the resource (in this case the buffer reader) indeed may throw an IOException. If you used a try-with-resources you would need to have a catch.
  • markspace
    markspace over 9 years
    That's not relevant to the OP's question though. The catch is still optional here.
  • Edwin Dalorzo
    Edwin Dalorzo over 9 years
    You continue without demonstrating that it is optional. Show the entire functions signature where you use this. You will have to declare a throws clause or either do a catch, irrespective of your use of try-with-resources.
  • markspace
    markspace over 9 years
    But again that's not the point. The catch clause on the code snippet I showed is optional. That code compiles just fine. I don't think a method signature or an nested try-catch is relevant to the OP's question. I'm just focusing on what he asked, nothing else.
  • Edwin Dalorzo
    Edwin Dalorzo over 9 years
    The problem with you example is that if I copy it and paste it in my main method it will give the exact the same compiler error that gave origin to the OP. Therefore, your explanation only states what the OP already knows without setting clear how it can be possible. Anyways, I rest my case.
  • markspace
    markspace over 9 years
    Well, my job isn't to show how how to use the code inside a method or your favorite game code or anything. The readLine() doesn't throw an exception, so the language specification doesn't require a catch. That's all that's relevant here.
  • Edwin Dalorzo
    Edwin Dalorzo over 9 years
    The readLine is not subject to try-with-resource, is the creation of the resource what matters, therefore, the relevant line in your code is that of the creation of the BufferedReader and not that of reading a line out of it.
  • Mer
    Mer over 9 years
    Thank you for the detailed answer. I was surprised, because I thought that try-with-resources was built to catch exceptions in the try that is specified as being "inside of" the try clause. I now see that the implementation of AutoCloseable must override close() so as not to throw the optional Exception, since the try-with-resources does not do this implicit catching.
  • jdphenix
    jdphenix over 9 years
    @Mer Language specs are always a good resource for these types of question.