Java try with resource exception

Exception Scenarios for Java’s try-with-resources

Have you ever ran into an exception thrown by a try-with-resources block and wondered how it works? This article observes the behavior of try-with-resources under different scenarios and explains what is going on. Support for try-with-resources was added in java 7 and has been enhanced in java 9. A try-with-resources block is able to automatically close resources when execution of the block completes. There are many different scenarios where try-with-resources will throw exceptions. This article explores those scenarios. If you are following along with the test examples the TestResource class is attached at the bottom of this article. TestResource is a mock object used to simulate a resource. It can be configured to fail the work() and close() methods. The createFailure() method simulates a failure to create a resource within a try block.

Creating Resources

Declare and initialize resource

try(var r = new TestResource())  //work with resource here > 

Resource Specification — «A resource specification uses variables to denote resources for the try statement, either by declaring local variables with initializer expressions or by referring to suitable existing variables. An existing variable is referred to by either an expression name (§6.5.6) or a field access expression (§15.11).» —Java Language Specification First r is declared and initialized. After the try block executes r is automatically closed and goes out of scope.

creating resource "resource" closing resource "resource" 

declare resource only

In java 7 a resource needed to be declared and initialized in the resource specification. Since java 9 initialized is not required as long as the variables is effectively final. Here is an example:

try(r)  //work with resource here > 

multiple resources

try(var r1 = new TestResource("r1"); var r2 = new TestResource("r2"))  //work with resource here > 
creating resource "r1" creating resource "r2" closing resource "r2" closing resource "r1" 

when creation fails with one resource

try(var r1 = createFailure())  //work with resource here > 
create failure java.io.IOException: create failure at com.github.moaxcp.trywithresources.TestResource.createFailure(TestResource.java:12) at com.github.moaxcp.trywithresources.TestTryWithResources.creat_fails(TestTryWithResources.java:35) 
try(var r1 = createFailure())  //work with resource here > catch (IOException e)  System.out.println("caught exception " + e); > 
create failure caught exception java.io.IOException: create failure 

when creation fails with multiple resources

try(var r1 = new TestResource("r1"); var r2 = createFailure())  //work with resource here > catch (IOException e)  System.out.println("caught exception " + e); > 
creating resource "r1" create failure closing resource "r1" caught exception java.io.IOException: create failure 

Working with resources

Now that we know the mechanics of creating a resoruce in a try-with-resources block lets examine working with resources inside the block.

Working with one resource

try(var r = new TestResource())  r.work(); > 
creating resource "resource" performing work with resource "resource" closing resource "resource" 

when the work fails

What happens with the work() method throws an exception? This can be done by setting the workFailure flag to true on the TestResource .

try(var r = new TestResource(true, false))  r.work(); > 
creating resource "resource" performing work with resource "resource" work failure with resource "resource" closing resource "resource" work failure with resource "resource" java.io.IOException: work failure with resource "resource" at com.github.moaxcp.trywithresources.TestResource.work(TestResource.java:47) at com.github.moaxcp.trywithresources.TestTryWithResources.work_with_resource_fails(TestTryWithResources.java:68) 

when work fails with multiple resources

When work fails with multiple resources the resources are closed in reverse order and the exception is caught or thrown.

try(var r1 = new TestResource("r1", false, false); var r2 = new TestResource("r2", true, false))  r1.work(); r2.work(); > 
creating resource "r1" creating resource "r2" performing work with resource "r1" performing work with resource "r2" work failure with resource "r2" closing resource "r2" closing resource "r1" work failure with resource "r2" java.io.IOException: work failure with resource "r2" at com.github.moaxcp.trywithresources.TestResource.work(TestResource.java:47) at com.github.moaxcp.trywithresources.TestTryWithResources.work_with_multiple_resources_fails(TestTryWithResources.java:76) 

As you can see, when r2.work() fails the resources are closed in reverse order and the exception is thrown.

Closing resources

As show before, a try-with-resources block will automatically close the resource but what happens when the close fails?

when close fails with one resource

try(var r = new TestResource(false, true))  r.work(); > 
creating resource "resource" performing work with resource "resource" closing resource "resource" close failure with resource "resource" close failure with resource "resource" java.io.IOException: close failure with resource "resource" at com.github.moaxcp.trywithresources.TestResource.close(TestResource.java:56) at com.github.moaxcp.trywithresources.TestTryWithResources.close_with_resource_fails(TestTryWithResources.java:84) 

When close fails with two resources

try(var r1 = new TestResource("r1", false, true); var r2 = new TestResource("r2", false, true))  r1.work(); r2.work(); > 

Since resources are closed in reverse order the exception from r2 will suppress the exception from r1 .

creating resource "r1" creating resource "r2" performing work with resource "r1" performing work with resource "r2" closing resource "r2" close failure with resource "r2" closing resource "r1" close failure with resource "r1" close failure with resource "r2" java.io.IOException: close failure with resource "r2" at com.github.moaxcp.trywithresources.TestResource.close(TestResource.java:56) at com.github.moaxcp.trywithresources.TestTryWithResources.close_with_two_resources_fails(TestTryWithResources.java:92) Suppressed: java.io.IOException: close failure with resource "r1" at com.github.moaxcp.trywithresources.TestResource.close(TestResource.java:56) at com.github.moaxcp.trywithresources.TestTryWithResources.close_with_two_resources_fails(TestTryWithResources.java:89) 

When work and close fails

try(var r1 = new TestResource("r1", true, true); var r2 = new TestResource("r2", true, true))  r1.work(); > 
creating resource "r1" creating resource "r2" performing work with resource "r1" work failure with resource "r1" closing resource "r2" close failure with resource "r2" closing resource "r1" close failure with resource "r1" work failure with resource "r1" java.io.IOException: work failure with resource "r1" at com.github.moaxcp.trywithresources.TestResource.work(TestResource.java:47) at com.github.moaxcp.trywithresources.TestTryWithResources.work_and_close_with_two_resources_fails(TestTryWithResources.java:98) . Suppressed: java.io.IOException: close failure with resource "r2" at com.github.moaxcp.trywithresources.TestResource.close(TestResource.java:56) at com.github.moaxcp.trywithresources.TestTryWithResources.work_and_close_with_two_resources_fails(TestTryWithResources.java:97) . 88 more Suppressed: java.io.IOException: close failure with resource "r1" at com.github.moaxcp.trywithresources.TestResource.close(TestResource.java:56) at com.github.moaxcp.trywithresources.TestTryWithResources.work_and_close_with_two_resources_fails(TestTryWithResources.java:97) . 88 more 

Summary

Try-with-resources is a very helpful tool when dealing with resources. It is especially helpful when dealing with multiple resources. It saves the developer from having to write correct closing code. It also makes suppressed exceptions available so developers know exactly what failures occurred. This article outlines different mechanics of try-with-resources in different scenarios. Can you think of any other scenarios for try-with-resources?

TestResource

Before I start showing examples there is some code for a TestResource and a failing factory method that is needed.

class TestResource implements AutoCloseable  private final String name; private final boolean workFailure; private final boolean closeFailure; public static TestResource createFailure() throws IOException  System.out.println("create failure"); throw new IOException("create failure"); > public TestResource()  name = "resource"; System.out.println("creating resource \"" + name + "\""); workFailure = false; closeFailure = false; > public TestResource(String name)  System.out.println("creating resource \"" + name + "\""); this.name = name; workFailure = false; closeFailure = false; > public TestResource(boolean workFailure, boolean closeFailure) throws IOException  this.name = "resource"; System.out.println("creating resource \"" + name + "\""); this.workFailure = workFailure; this.closeFailure = closeFailure; > public TestResource(String name, boolean workFailure, boolean closeFailure) throws IOException  System.out.println("creating resource \"" + name + "\""); this.name = name; this.workFailure = workFailure; this.closeFailure = closeFailure; > public void work() throws IOException  System.out.println("performing work with resource \"" + name + "\""); if(workFailure)  System.out.println("work failure with resource \"" + name + "\""); throw new IOException("work failure with resource \"" + name + "\""); > > @Override public void close() throws IOException  System.out.println("closing resource \"" + name + "\""); if(closeFailure)  System.out.println("close failure with resource \"" + name + "\""); throw new IOException("close failure with resource \"" + name + "\""); > > > 

Источник

Читайте также:  К каким языкам относится html
Оцените статью