2015-12-15 11 views
11

私は複数のCloseableリソースを管理するJavaクラスを作成しようとしています。 C++ソリューションは、リソースの数が多い、簡単かつ容易に拡張することになります。Javaで閉じるオブジェクトを作成するには?

class composed_resource 
{ 
    resource_a a; 
    resource_b b; 
    resource_c c; 

    composed_resource(int x) 
     : a(x), b(x), c(x) 
    { } 

    ~composed_resource() 
    { } 
}; 

私の素朴なJavaソリューション:

public class ComposedResource implements Closeable 
{ 
    private final ResourceA a; 
    private final ResourceB b; 
    private final ResourceC c; 

    public ComposedResource(int x) /* throws ... */ { 
     a = new ResourceA(x); 
     try { 
      b = new ResourceB(x); 
      try { 
       c = new ResourceC(x); 
      } catch (Throwable t) { 
       b.close(); 
       throw t; 
      } 
     } catch (Throwable t) { 
      a.close(); 
      throw t; 
     } 
    } 

    @Override 
    public void close() throws IOException { 
     try { 
      a.close(); 
     } finally { 
      try { 
       b.close(); 
      } finally { 
       c.close(); 
      } 
     } 
    } 
} 

A若干改善バージョン:

public class ComposedResource2 implements Closeable 
{ 
    private final ResourceA a; 
    private final ResourceB b; 
    private final ResourceC c; 

    public ComposedResource2(int x) /* throws ... */ { 
     try { 
      a = new ResourceA(x); 
      b = new ResourceB(x); 
      c = new ResourceC(x); 
     } catch (Throwable t) { 
      close(); 
      throw t; 
     } 
    } 

    @Override 
    public void close() throws IOException { 
     try { 
      if (a != null) a.close(); 
     } finally { 
      try { 
       if (b != null) b.close(); 
      } finally { 
       if (c != null) c.close(); 
      } 
     } 
    } 
} 

があります例外安全性を維持しながら、ネストされたtry-catchブロックを回避するより洗練されたソリューションそれは3つのリソースで管理可能ですが、それ以上のものは扱いにくくなっています。 (それはローカルスコープだった場合、私はちょうど「してみてください-と資源」ステートメントを使用することができますが、それはここでは適用されませんです。)


java.rmiで作業しながら、私はこれについて考えました。コンストラクタでは、レジストリの作成/参照、オブジェクトの検索、オブジェクトのエクスポートを行っています。 close()は、オブジェクトの登録を解除し、オブジェクトをアンエクスポートする必要があります。私はラッパーオブジェクトを作成してexport/unexportを処理することを考えました(RAIIを利用するためにC++でやったように)が、私はそれほど助けにならないことに気付きました(私はJavaの専門家ではない、私は大学で使う必要があります)。

現時点では、私は上記のComposedResource2のようなものを使用しており、正常に動作します。しかし今、より洗練されたソリューションがあるかどうかを知りたいと思っています。

+2

ユースケースを提示できますか?たぶん具体的な例を使って作業すると、抽象的な問題よりも優れた答えが得られるでしょう... –

+1

リソースは試用できません。 –

+2

1)コンストラクタでリソースを作成しないでください - 理想的には、フィールドにパラメータを割り当てるだけで、RAIIはここでは使用できません。 2)可能であればtry-with-resourcesを使用してください(おそらくコンストラクタが "代入モード"でしか動作しない場合はもっと可能でしょう)。 3)複数の 'Closeable'インスタンスを1つのインスタンスに結合する' Closeable'デコレータを書くことができます。 4)あるいは、あなたはGuava 'com.google.common.ioを使うことができます。より近くに。 –

答えて

11

このようなtry-with-resoucesを使用してください。

@Override 
public void close() throws IOException { 
    try (Closeable cc = c; 
     Closeable bb = b; 
     Closeable aa = a;) { 
     // do nothing 
    } 
} 
+0

初期化エラーのためにリソースがnullの場合はどうなりますか? – AdamSkywalker

+2

@AdamSkywalker bがnullの場合、aとcは閉じます。 – saka1029

+2

@AdamSkywalker 'cc'、' bb'、 'aa'がすべてNULLであっても、' try-with-resources'はJavaではnullセーフです。何も失敗しません。また、初期化されていないオブジェクトや初期化されていないオブジェクトを使用して初期化例外をスローすることはできません。最も良いケースは、常によく初期化されたオブジェクトです。 –

1

このようにclose()を変更するとどうなりますか?

@Override 
public void close() { 
    close(a); 
    close(b); 
    close(c); 
} 

public void close(Closeable closeable) throws IOException{ 
     if (closeable != null){ 
      closeable.close(); 
     } 
} 

は、私はあなたが望むようComposedResourceは、できるだけ多くの資源を持っていますので、そのよりきれいな...

はまた、あなたが「Closeables」として3つのリソースを管理し、配列にそれらを置くことができると思います。このような何かやって:

public class ComposedResource{ 
    List<Closeable> resources = new ArrayList<Closeable>(); 

    public void add(Closeable c){ 
     resources.add(c); 
    } 

    @Override 
    public void close(){ 
     for (Closeable r : resources){ 
      close(r); 
     } 
    } 

    public void close(Closeable c){ 
     try{ 
      c.close(); 
     catch (IOException e){ 
      log(e); 
     } 
    } 
} 

をですから、リソースを追加します。

ComposedResource c = new ComposedResource(); 
c.add(new Resource1()); 
c.add(new Resource2()); 
c.add(new Resource3()); 
... 
// do nice thinks 
// and, to close; 
c.close(); 

編集:

@Mohitカンワルは、そのように例外をスローすることを提案:

@Override 
public void close() throws IOException { 
    for (Closeable r : resources){ 
     r.close(r); 
    } 
} 

私のコードを編集した@Liiは、この1つの例外を実行するとすべてのリソースを閉じることができなくなると言います私はMohitの編集を拒否しました。

+2

リソースが閉じられていない場合、ロギング後に例外eをスローしないでください。 –

+3

解決策では、最初のリソースが閉じられたときにスローされた場合、後続のリソースは閉じられません。それがうまくいくはずはありません! – Lii

+0

@inigoD私は今それを理解しています。間違った編集をおかしなさい。私はそれがあなたにダウンボートをかけたので、同じもののために旗を掲げました。もう一度申し訳ありません:( –

関連する問題