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

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.

Related

Does Java's try-with-resources catch errors or just exceptions?

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!

Will this release my resources after being used?

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.

Why is close() method of the resource called before catch in a try-with-resources construct in Java?

I happened to realize, that this is the case. See this example below:
public class AutoClosableTest {
public static void main(String[] args) throws Exception {
try (MyClosable instance = new MyClosable()) {
if (true) {
System.out.println( "try" );
throw new Exception("Foo");
}
} catch( Exception e ) {
System.out.println( "Catched" );
} finally {
System.out.println( "Finally" );
}
}
public static class MyClosable implements AutoCloseable {
#Override
public void close() throws Exception {
System.out.println( "Closed." );
}
}
}
It prints:
try
Closed.
Catched
Finally
Question
The try-with-resources is designed to avoid the messy finally sections with null checks and to avoid the leaked resources. Why are the resources closed BEFORE the catch section? What is the reason/idea/limitation behind it?
The answer can be found in JLS §14.20.3.2; the key parts are the last two paragraphs, particularly the last sentence of the penultimate paragraph (I've emphasized it):
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.

Who catch exception, arise in close method?(try-with-resources)

interface AutoClosable has following method declaration:
void close() throws Exception
Thus we see that method close can throws Exception.
When I write code try-with resources it is looks like this:
private static void printFileJava7() throws IOException {
try(FileInputStream input = new FileInputStream("file.txt")) {
int data = input.read();
while(data != -1){
System.out.print((char) data);
data = input.read();
}
}
}
At this code is absent Exception handling.
I don't understand what happens if close method throws exception.
Java catches and suppresses exceptions thrown by the close method in a try-with-resources block.
You can read more about this here, see in particular the paragraph after the second code sample. http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
You are right that close() method defined in AutoClosable throws exception. However other interface named Closable that extends AutoClosable redefines this method as following:
void close() throws IOException
All IO related classes implement Closable, so their close() method throws IOException. But your method throws it too, so in your code no-one catches this exception. As always it will be caught by upper layer of your application or by JVM itself if no-one catches it before.
From the jls about Compile-Time Checking of Exceptions
When interfaces are involved, more than one method declaration may be overridden by a single overriding declaration. In this case, the overriding declaration must have a throws clause that is compatible with all the overridden declarations (§9.4.1).
So when you have something like
static class AC implements AutoCloseable {
#Override
public void close() throws Exception {
throw new Exception("btooom!");
}
public void ac() {
System.out.println("no");
}
}
public static void main(String[] args) throws Exception {
try(AC ac = new AC()) {
ac.ac();
}
}
then you are forded to either add a catch clause to the surrounding try block or add a throws declaration.
In the case of FileInputStream and to apply what the jsl states, the AutoCloseable's close method is overriden from Closeable's, hence you only have to catch an IOException or add it to throws clause.
Further the javadocs of AutoCloseable#close states
While this interface method is declared to throw Exception, implementers are strongly encouraged to declare concrete implementations of the close method to throw more specific exceptions, or to throw no exception at all if the close operation cannot fail.
The key to this particular scenario is the "supressed exception".
"Whenever an exception is thrown within the body, and then followed
by an exception thrown by the try-with-resources statement, only the
exception thrown in the body of the try is eligible to be caught by
the exception handling code. All other exceptions are considered supressed exceptions"
A concept that is new with Java 7.SO you will get the same output as when only the printfileJava7 class throws an exception, since the CloseException thrown by the close() method would be suppressed.
Please refer to When two exceptions are thrown by the try-with-resources construct link.Which have taken exact scenario what You have asked
You need to have a catch block followed by try in the method printFileJava7(). If you don't want to catch it here, you need handle it in the method which calls the method printFileJava7(). We have to catch in one of the layers otherwise it will be propagated back to the calling client.

Java 1.5 compatible pattern that will handle all possible exceptions without exception swallowed/lost and resources closing?

I have some method that uses some resources that should be closed at the end and the method itself and resource closing could throw everything including IO Connection and so on exceptions, some Runtime exceptions and even Errors (everything what inherits Throwable OOM is often case.).I want to handle all Exceptions without losing information and to send/throw the most important exception to the client (supposingly the runtime exceptions/errors?) This is the pattern I use (it's java 1.5 so I can't use resource features from 1.7):
Throwable thr=null;
try {
methodThatCouldThrowCheckedExceptionAndErrorAndRuntimeExcpetion();
log("method succesfully executed.");
} catch (IKnowThisException ikte) {
//Exception will be not lost
log("Method was not executed ,and I can suggest further actions",itke);
thr=ikte;
} catch (Throwable t) {
// This exception will be not lost too
log("Method was not executed ,and I don't know why.",t);
thr=t;
} finally {
try{
// The method below - of course contains the standard null checkers.
closeResourcesMethodThatCouldThrowEverythingToo();
log("resources were closed.");
} catch (IKnowThisEscpetionToo iktet) {
log(iktet);
throw new IllegalStateException("Resources were not closed , because of the known exception and I can suggest some actions" , ijtet);
} catch (Throwable t) {
log(t);
throw new IllegalStateException("Resources were not closed and I don't know why" , t);
}
// in case resources are closed we can re-throw exception from try{} block
if ( thr != null ) {
throw thr;
}
}
But I'm not completely sure it's the best approach .Here a similar approach i sused . But it does not handle unchecked exceptions (do I need to handle them?) Is there a case when I can lost valuable information? In the most examples I found nothing special is done about Errors/RuntimeExcpetions , but I want them logged. Is there a better approach? May be I should construct a more complicated chained exception to keep information compacted?
To preserve all of the errors, it would be best to use a custom exception class, that provides something like ARM's "suppressed exception" collection.
If the method throws an exception, this is the (cause of the) main exception. If closing resources raises additional exceptions, they are added to the main as suppressed exceptions.
If the method completes without failure, but closing resources raises an exception, the first becomes the main exception, and subsequent resource close failures are added to it as suppressed exceptions.
If a resource was intended to have side effects like writing a file or updating a database, the application needs to determine what to do when closing that resource fails. Using a general purpose mechanism that hides those resource closure exceptions would not allow the application to make that determination, and would only be useful in the rare cases where the application doesn't care if any output is actually produced.
I would look at how the compiler rewrites the try-with-resources pattern in Java 1.7. Below is a simple example of the pattern in source level 1.7, followed by a decompiled version with try-with-resources sugaring disabled:
// Original:
public void test() throws IOException {
try (final StringWriter writer = new StringWriter()) {
writer.write("This is only a test.");
}
}
// Decompiled:
public void test() throws IOException {
final StringWriter writer = new StringWriter();
Throwable t = null;
try {
writer.write("This is only a test.");
}
catch (Throwable t2) {
t = t2;
throw t2;
}
finally {
if (writer != null) {
if (t != null) {
try {
writer.close();
}
catch (Throwable t2) {
t.addSuppressed(t2);
}
}
else {
writer.close();
}
}
}
}
Sadly, the addSuppressed() method was only introduced in Java 1.7, but you could create a custom exception class that introduces this behavior, as #erickson suggests in his answer. If only one exception occurs, simply rethrow that one. Otherwise, replace it with the custom exception, wrap the original as the cause, and add any suppressed exceptions that occurred during closing of resources.
As I know, un-checked exception should not be handle. But you can handle by catching broader exception such as "Exception" before finally block.
I suggest you read my blog post Clean Up After Yourself (Grab my Close class) and then
import static com.frischcode.util.Close.close;
// Where ... is any number of things to close (in finally block - naturally).
close(...);

Categories