将资源移出try-with块

huangapple go评论62阅读模式
英文:

Move resource out of try-with

问题

我想创建一个包装资源的类实例。问题是:当构造函数抛出异常时,资源会丢失。我正在尝试找到解决方案。"Try-with-resource" 是一个看起来适合这种情况的结构,但我不能将资源从中移出。

例如,一个包装 HTTP 客户端的服务客户端:

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

  public ServiceClient create(String url) throws IOException {
    try (ClosableHTTPClient client = createHttpClient(url)) {
      return new ServiceClient(client);
    }  // 使 try-with 不在成功时关闭 `client`
  }

  public ClosableHTTPClient createHttpClient(String url) {
    return HttpClientBuilder.create()
        .setConnectionManager(createClosableConnectionManager()) // 在 `build` 抛出异常时必须关闭
        .build();
  }
}
英文:

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

答案1

得分: 0

构造函数抛出异常。

class Foo implements AutoClosable {

    private final Bar someResource;

    /**
     * @param someResource 要接管所有权的资源。
     */
    Foo(Bar someResource) {
        this.someResource = someResource;
        try {
            ...
        } catch (Throwable e) {
            someResource.close(); // 如果 this.close 不是 final 的。
            throw e;
        }
    }

    @Override public void close() { someResource.close(); }
    ...
}

唯一的解决方案是处理构造函数中抛出的任何异常
甚至连标准的 Java 类有时也会忽略具有负容量的 BufferedReader 将不会关闭其包装的 reader)。
英文:

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

huangapple
  • 本文由 发表于 2020年9月11日 17:30:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/63844348.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定