Search code examples
javatry-with-resources

Move resource out of try-with


I want to create a class instance which wraps a resource. The problem: when the constructor throws, the resource is lost. I'm trying to find a solution for that. Try-with-resource is a construct that seems good for that, but I can not move the resource out of it.

For example, a service client that wraps a HTTP client:

class ServiceClient implements Closeable {
  ServiceClient(ClosableHTTPClient client) { /* ... */ }
  public close() { client.close() }

  public ServiceClient create(String url) throws IOException {
    try (ClosableHTTPClient client = createHttpClient(url)) {
      return new ServiceClient(client);
    }  // make try-with do not close `client` on success
  }

  public ClosableHTTPClient createHttpClient(String url) {
    return HttpClientBuilder.create()
        .setConnectionManager(createClosableConnectionManager()) // must be closed, when `build` throws 
        .build();
  }
}

Solution

  • A constructor throwing an exception.

    class Foo implements AutoClosable {
    
        private final Bar someResource;
    
        /**
         * @param someResource whose ownership is taken over.
         */
        Foo(Bar someResource) {
            this.someResource = someResource;
            try {
                ...
            } catch (Throwable e) {
                someResource.close(); // If this.close is not final.
                throw e;
            }
        }
    
        @Override public void close() { someResource.close(); }
        ...
    

    The only solution is taking care of any exception thrown in the constructor. Event the standard java classes sometimes forget (a BufferedReader with negative capacity will not close its wrapped reader).