Try with Resources VS Try-Catch

Try With Resources vs Try-Catch

The main point of try-with-resources is to make sure resources are closed reliably without possibly losing information.

When you don't use try-with-resources there's a potential pitfall called exception-masking. When code in a try block throws an exception, and the close method in the finally also throws an exception, the exception thrown by the try block gets lost and the exception thrown in the finally gets propagated. This is usually unfortunate, since the exception thrown on close is something unhelpful while the informative one is the one thrown from within the try block. (So instead of seeing the SQLException that tells you which referential integrity constraint was violated, you're shown something like BrokenPipeException where closing the resource failed.)

This exception-masking is an annoying problem that try-with-resources prevents from happening.

As part of making sure exception-masking wouldn't lose important exception information, when try-with-resources was developed they had to decide what to do with the exceptions thrown from the close method.

With try-with-resources, if the try block throws an exception and the close method also throws an exception, then the exception from the close block gets tacked on to the original exception:

... there are situations where two independent exceptions can be thrown in sibling code blocks, in particular in the try block of a try-with-resources statement and the compiler-generated finally block which closes the resource. In these situations, only one of the thrown exceptions can be propagated. In the try-with-resources statement, when there are two such exceptions, the exception originating from the try block is propagated and the exception from the finally block is added to the list of exceptions suppressed by the exception from the try block. As an exception unwinds the stack, it can accumulate multiple suppressed exceptions.

On the other hand if your code completes normally but the resource you're using throws an exception on close, that exception (which would get suppressed if the code in the try block threw anything) gets thrown. That means that if you have some JDBC code where a ResultSet or PreparedStatement is closed by try-with-resources, an exception resulting from some infrastructure glitch when a JDBC object gets closed can be thrown and can rollback an operation that otherwise would have completed successfully.

Without try-with-resources whether the close method exception gets thrown is up to the application code. If it gets thrown in a finally block when the try block throws an exception, the exception from the finally block will mask the other exception. But the developer has the option of catching the exception thrown on close and not propagating it.

Java: try-with-resources vs try-catch-finally about order of autoclosing

As ever, the answer is in the JLS - in this case, section 14.20.3.2. Basically, if you have catch or finally blocks in your try-with-resources statement, that's converted into a "normal" try/catch/finally block which contains a try-with-resources statement without your specified catch/finally block - but with the one that calls close automatically. So your try-with-resources snippet is effectively:

try {
try (Bum bum = new Bum()) {
bum.bu();
}
} catch (Exception ex){
System.out.println("Exception");
//ex.printStackTrace();
}

Which is in turn roughly equivalent to:

try {
Bum bum = new Bum();
try {
bum.bu();
} finally {
// It's more complicated than this...
bum.close();
}
} catch (Exception ex){
System.out.println("Exception");
//ex.printStackTrace();
}

So the "inner" finally block which closes the resource is executed before the catch block in the "outer" try statement.

What's the purpose of try-with-resources statements?

It was introduced because of some resources used in Java (like SQL connections or streams) being difficult to be handled properly; as an example, in java 6 to handle a InputStream properly you had to do something like:

InputStream stream = new MyInputStream(...);
try {
// ... use stream
} catch(IOException e) {
// handle exception
} finally {
try {
if(stream != null) {
stream.close();
}
} catch(IOException e) {
// handle yet another possible exception
}
}

Do you notice that ugly double try? now with try-with-resources you can do this:

try (InputStream stream = new MyInputStream(...)){
// ... use stream
} catch(IOException e) {
// handle exception
}

and close() is automatically called, if it throws an IOException, it will be supressed (as specified in the Java Language Specification 14.20.3) . Same happens for java.sql.Connection

try catch vs try-with-resources

FileNotFoundException is a subclass of IOException. By catching the latter, you're catching the former too. It has nothing to do with try-catch vs. try-with-resources.

Is Try-Catch More or Less Expensive Than Try-With-Resources

  1. try-catch is not the expensive part. Throwing the exception is (generating the stacktrace).
  2. "Expensive" above means "costs some microseconds".
  3. try-with-resources is just try-catch with proper code needed to reliably close the resource.
  4. Your measurement code cannot prove anything due to all the well-known pitfalls of trying to measure performance within an optimizing runtime such as HotSpot. You need to warm up, repeat the same many times, and much more.
  5. If your result is above 10 ms, then clearly you cannot have an issue with try-catch, which can altogether impose an overhead of several microseconds.

Resource leak for file processing, try with resources VS try-catch-finally with file.close()

The biggest difference is the danger of exception-masking with the try-finally approach. If you're not careful to catch anything thrown within the finally block on close, you can mask any exception thrown within the try block. That means that if the code within the try block throws an exception, then the code within the finally throws an exception, the exception that gets propagated is the one from the finally block (which is usually not the one you would want to see).

try-with-resources eliminates the danger of exception-masking by making sure that if an exception is thrown from the try block, any exception thrown by the close method gets tacked on as a suppressed exception.

The case where no exception is thrown in the try block but an exception gets thrown on close is handled differently by try-with-resources than it would be if you use try-finally and catch anything thrown in the finally block. With try-with-resources the exception thrown on close would be thrown (since there's not an exception to add it to as a suppressed exception), where the usual approach with try-finally is to eat or log any exception thrown from the finally method. So if you don't want a failure on close to cause an exception to be thrown, disrupting some logic that otherwise worked correctly, you may want to avoid try-with-resources for that.

A significant difference is how try-with-resources allows multiple resources. People writing try-finally blocks usually get impatient with nesting try blocks and cause bugs with shortcuts such as putting too many close statements in a finally block (so if one fails the remaining ones don't execute, causing a resource leak). try-with-resources guarantees closing the resources in the right order on the way out so that no nested blocks are required.

Try-with-resources: Must I throw or catch the close() method's exceptions?

Quote from Java Language Specification ($14.20.3.2):

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

    Catchesopt

    Finallyopt

is given by the following translation to a basic try-with-resources statement
(§14.20.3.1) nested inside a try-catch or try-finally or try-catch-finally
statement:

    try {

        try ResourceSpecification

            Block

    }

    Catchesopt

    Finallyopt

The effect of the translation is to put the ResourceSpecification "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.

So, basically, wrapper is already implemented

How to catch exceptions from try-with-resources?

The only exception getResourceAsStream(name) could throw is a NullPointerException and that too, when the name is null. It will not throw any other exception even if the resource is not found.

If you want your code to throw a FileNotFoundException when resource is missing, then use new FileInputStream(String resourceName) (which throws the required file not found exception) to load your resource instead of getResourceAsStream()

try-with-resources details

Whenever language related details are needed, the most complete reference is the Java Language Specification (just Google it). For the try-with-resources statement, you can read section 14.20.3 which states that the following:

try ({VariableModifier} R Identifier = Expression ...)
Block

is translated to

{
final {VariableModifierNoFinal} 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();
}
}
}
}

In your first example, the resource R is BufferedReader, the Identifier is br and the Expression is new BufferedReader(new FileReader(filePath)). It follows that only the BufferedReader is closed in the implicit finally block. The finally block will not call close on the FileReader because it is not part of the resource declaration itself. However, it happens that the implementation of BufferedReader.close() internally calls the close method of the wrapped FileReader. So the answer to the first question is yes simply because the wrapper object closed it (following the common wisdom that a resource should release any wrapped resource when being itself released), not because of the try-with-resources.

In the second example:

private static BufferedReader buf1;

public static void main(String[] args) throws IOException {
//some code
try (BufferedReader buf2 = buf1)
{

}
}

the answer depends on the some code. Here buf2 and buf1 both refer to the same object in memory. If this "some code" initializes buf1 to some object, then this object will be closed since buf2 also refers to it. If not and buf1 is null (and therefore buf2 is null), then nothing will be closed because of the null check in the implicit finally shown above.



Related Topics



Leave a reply



Submit