0

tryAutoCloseable-with-resources は素晴らしいですが、複数のオブジェクトをラップするクラスを作成する場合、効果的なリソース管理にはまだ十分ではないように思えます。たとえば、

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

このラッパーには少なくとも 2 つの問題があります。

  1. 「bad-path」が無効で割り当てがr2スローされる場合、r1は閉じられません。
  2. ラッパーの構築が成功した後にr1.closeスローされた場合、r2は閉じられません。

これらの問題はすべて対処できますが、2 つのリソースのみをラップする場合でも、ラッパーの作成は非常に簡単ではなく、エラーが発生しやすくなります。

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

ラッパーの作成を容易にするヘルパー クラスまたはその他の方法はありますか?

4

2 に答える 2

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");
    }
  }
}
于 2015-11-30T23:31:17.810 に答える