Exception Scenarios for Java's try-with-resources
Tags: java, beginners, tutorial
Published: 2020-07-28 16:35:54

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](#TestResource) 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-with-resources starts by declaring a resource inside a [resource specification](https://docs.oracle.com/javase/specs/jls/se11/html/jls-14.html#jls-14.20.3-200).

```java
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:

```java
try(r) {
  //work with resource here
}
```

## multiple resources

Multiple resources can be used in a try-with-resources block. 

```java
try(var r1 = new TestResource("r1"); var r2 = new TestResource("r2")) {
    //work with resource here
}
```

Resources are created in order and closed in reverse order.

```
creating resource "r1"
creating resource "r2"
closing resource "r2"
closing resource "r1"
```

## when creation fails with one resource

Here is an example of what happens when creation fails.

```java
try(var r1 = createFailure()) {
    //work with resource here
}
```

An exception is thrown.

```
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)
```

The exception can be caught with a catch block.

```java
try(var r1 = createFailure()) {
    //work with resource here
} catch (IOException e) {
    System.out.println("caught exception " + e);
}
```

An exception is thrown and caught.

```
create failure
caught exception java.io.IOException: create failure
```

## when creation fails with multiple resources

Another scenario is what happens when creation fails with multiple resources.

```java
try(var r1 = new TestResource("r1"); var r2 = createFailure()) {
    //work with resource here
} catch (IOException e) {
    System.out.println("caught exception " + e);
}
```

`r1` is created, `r2` fails to create, then `r1` is closed, and then the catch block executes.

```
creating resource "r1"
create failure
closing resource "r1"
caught exception java.io.IOException: create failure
```

**Notice** that `r1` is closed before the catch block is executed.

# 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

```java
try(var r = new TestResource()) {
    r.work();
}
```

In this case the resource is create, work is performed, and the resource is closed.

```
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`.

```java
try(var r = new TestResource(true, false)) {
    r.work();
}
```

When work fails the resource should be close and then the exception can be caught or thrown.

```
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)
```

In this case if there was a catch block it would be executed after the resource closes.

## 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.

```java
try(var r1 = new TestResource("r1", false, false); var r2 = new TestResource("r2", true, false)) {
    r1.work();
    r2.work();
}
```

Here `r2` is setup to fail when the `work()` method is called.

```
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

Failing close can be achieve by setting the `closeFailure` flag to `true` on the `TestResource`.

```java
try(var r = new TestResource(false, true)) {
    r.work();
}
```

When close fails the exception is thrown.

```
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

Here r1 and r2 will fail to close.

```java
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)
```

**Notice** - The exception from closing `r1` is suppressed by the exception from `r2`.

# When work and close fails

Now we are getting to the interesting scenario.

```java
try(var r1 = new TestResource("r1", true, true); var r2 = new TestResource("r2", true, true)) {
    r1.work();
}
```

In this case `work` will fail but so will closing the two resources.

```
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
```

Here the work failure is thrown and the two close failures are suppressed.

# 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<a name="TestResource"></a>

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

```java
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 + "\"");
        }
    }
}
```