包装多个AutoCloseables

时间:2014-07-11 19:23:31

标签: java autocloseable

try - with-resources很好,所有这一切,但在我看来,在创建包装多个AutoCloseable对象的类时,仍然不足以进行有效的资源管理。例如,考虑

import java.io.*;

class AutocloseableWrapper implements AutoCloseable {
    private FileReader r1;
    private FileReader r2;

    public AutocloseableWrapper(String path1, String path2) throws IOException {
        r1 = new FileReader(path1);
        r2 = new FileReader(path2);
    }

    @Override
    public void close() throws IOException {
        r1.close();
        r2.close();
    }

    public static void main(String[] args) throws IOException {
        try (AutocloseableWrapper w = new AutocloseableWrapper("good-path", "bad-path")) {
                System.out.format("doing something\n");
                throw new IOException("doing something in main");
            }
    }
}

此包装器至少存在两个问题:

  1. 如果“错误路径”无效并导致r2投降,则r1未关闭。
  2. 如果包装器构造成功但r1.close抛出,则r2未关闭。
  3. 所有这些问题都可以解决,但是编写包装器变得非常重要且容易出错,即使只包装了两个资源:

    import java.io.*;
    
    class AutocloseableWrapper implements AutoCloseable {
        private FileReader r1;
        private FileReader r2;
    
        public AutocloseableWrapper(String path1, String path2) throws IOException {
            r1 = new FileReader(path1);
            try {
                r2 = new FileReader(path2);
            }
            catch (IOException e) {
                try {
                    r1.close();
                }
                catch (IOException e2) {
                    e.addSuppressed(e2);
                }
                throw e;
            }
        }
    
        @Override
        public void close() throws IOException {
            IOException e = null;
            try {
                r1.close();
            }
            catch (IOException e1) {
                e = e1;
            }
    
            try {
                r2.close();
            }
            catch (IOException e2) {
                if (e == null)
                    throw e2;
                else {
                    e.addSuppressed(e2);
                    throw e;
                }
            }
        }
    
        public static void main(String[] args) throws IOException {
            try (AutocloseableWrapper w = new AutocloseableWrapper("good-path", "bad-path")) {
                    System.out.format("doing something\n");
                    throw new IOException("doing something in main");
                }
        }
    }
    

    是否有一些帮助程序类或任何其他方法使编写包装器更容易?

2 个答案:

答案 0 :(得分:2)

你应该启用编译器解包的语法代码....你可以在这里找到Oracle文章: - http://www.oracle.com/technetwork/articles/java/trywithresources-401775.html

提出问题,如果你有一个包装器,你可以做这样的事情

@Override
public void close() throws IOException {
    Throwable t = null;
    try {
        r1.close();
    } catch (Throwable t1) {
        t = t1;
        throw t1;
    } finally {
        if (t != null) {
            try {
                r2.close();
            } catch (Throwable t2) {
                t.addSuppressed(t2);
            }
        } else {

            r2.close();
        }
    }
}

注意:由于Java中的精确重新抛出功能 7

,这将起作用

答案 1 :(得分:1)

您可以使用通用资源包装器,例如:

public class CloseableChain implements AutoCloseable {
  private AutoCloseable r1;
  private CloseableChain r2;

  public void attach(AutoCloseable r) {
    if (r1 == null) {
      r1 = r;
    } else {
      if (r2 == null) {
        r2 = new CloseableChain();
      }
      r2.attach(r);
    }
  }

  public void close() throws Exception {
    if (r1 == null) {
      return;
    }
    Throwable t = null;
    try {
      r1.close();
    } catch (Throwable t1) {
      t = t1;
      throw t1;
    } finally {
      if (r2 != null) {
        if (t != null) {
          try {
            r2.close();
          } catch (Throwable t2) {
            t.addSuppressed(t2);
          }
        } else {
          r2.close();
        }
}}}}

然后你可以将你的代码重构为:

import java.io.*;

class AutocloseableWrapper implements AutoCloseable {
  private CloseableChain chain;
  private FileReader r1;
  private FileReader r2;
  private FileReader r3;

  public AutocloseableWrapper(String path1, String path2) throws IOException {
    chain = new CloseableChain();
    r1 = new FileReader(path1);
    chain.attach(r1);
    r2 = new FileReader(path2);
    chain.attach(r2);
    // and even more...
    r3 = new FileReader("whatever");
    chain.attach(r3);
  }

  @Override
  public void close() throws IOException {
    chain.close();
  }

  public static void main(String[] args) throws IOException {
    try (AutocloseableWrapper w = new AutocloseableWrapper("good", "bad")) {
      System.out.format("doing something\n");
      throw new IOException("doing something in main");
    }
  }
}