31

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.

3
  • Try compiling at the command line without Eclipse Commented Aug 26, 2014 at 2:25
  • 2
    You can provide an AutoClosable implementation that do not throw an exception in whose case you would not need a catch anything, or you could add a throws clause in your method signature in whose case you wouldn't need a catch clause. Commented Aug 26, 2014 at 2:38
  • Thanks for the answer and the note about the throws on the containing method, Edwin. I'd forgotten that doing that would relieve the try statement from having to catch the exception. Commented Aug 26, 2014 at 5:38

5 Answers 5

27

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.

Sign up to request clarification or add additional context in comments.

2 Comments

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.
@Mer Language specs are always a good resource for these types of question.
3

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"); } } 

Comments

1

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()" ); } } } 

Comments

0

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.

Comments

-1

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.

9 Comments

I don't get it. This example does not use try-with-resources.
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.
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.
That's not relevant to the OP's question though. The catch is still optional here.
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.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.