2017-07-19 12 views
3

私は自分のコードをモジュール化しようとしていますが、AutoCloseableを実装しているオブジェクトを渡しています。私はfoo1のからfoo2はを呼び出すだけでなく、他のクラスが別途foo2は使用することができるようにしたい同じAutoCloseableオブジェクトを持つ複数のメソッドでtry-with-resourcesを使用する

public class MyClass { 
    public void foo1() { 
     // Connection implements AutoCloseable 
     try (Connection conn = createConnection()) { 
      foo2(conn); 
      // is the connection closed or the behavior unpredictable? 
      conn.doSomethingElse(); 
    } 
    } 

    public void foo2(Connection conn) { 
     try (conn) { 
      // do something with the Connection 
     } 
    } 
} 

:私はfoo1のとfoo2は2つのパブリックメソッドを持っているとしましょう。

public class OtherClass { 
    public void doSomething() { 
     MyClass myClass = new MyClass(); 
     myClass.foo2(createConnection()); 
    } 
} 

これは、foo2()の呼び出し後にfoo1()で接続が閉じられることになりますか?または、try-with-resourceを呼び出しメソッド(例えば、OtherClassのdoSomething()など)に配置する必要がありますか?

+0

試してみる価値とは、と '..試すfinally'のためだけsyntaxic糖であります'finally'の' close'を呼び出します。だからそれは 'foo2'の呼び出しの後に閉じられます。 – litelite

+1

申し訳ありませんが、foo2もコンパイルしますか?私のIDEは確かに私にそれを許可しません。そして、私が言語仕様で見ることができる限り、try-with-resourcesは中括弧で宣言された新しい変数を必要とします。 – Ordous

答えて

1

はい、foo2が接続を終了するので、制御がfoo1に戻ったときに無効になります。それについて何も予測できない。

物事を作成するのと同じコードで物事を閉じさせることは良いルールです。しかし、これらのものを入れ子にして、同じ接続とトランザクションを共有できるようにすることは良いことです。 1つの解決策は、これらのデータアクセス方法のそれぞれがパラメータとして接続を受け取り、接続を取得してそれが閉じられることを保証する外部層を有することであろう。

あなたは基本的にSpringを少しずつ改革しようとしています。 Springでは、同じ接続を使用できるサービスを持つことができ、トランザクション間のやりとりの方法や方法を制御できます。これは、AOPを使用して、スレッドローカルデータ構造からのスレッドの現在の接続を取得する周囲のアドバイスでオブジェクトをラップします。はるかに簡単に春(または任意のコンテナ)を使用します。

+0

Spring内でこれがより良く制御される方法を拡張できますか?それが元の質問の意図ではありませんでしたが、私はSpringがこれをどのように処理できるかを見ることに興味があります。 – acvcu

2

foo1メソッドは、foo2がそれを使用した後に接続を閉じます。 foo2は接続を閉じる必要はありません。予期せぬ副作用を引き起こしています。例えば。 conn.doSomethingElse()foo1の中に呼び出すと、foo2への呼び出しによって接続が切断されているため、動作しないことがわかります。メソッド名がこの副作用を明らかにしないので、principle of least astonishmentの違反です。

foo2AndCloseTheConnectionと呼んだ場合は、それが何であるかを明確にしますが、親密なルールに従うことをお勧めします。クローズ可能なメソッドはクローズするメソッドでなければなりません。これを一貫して実行すると、開いているものがその関数によって閉じられているかどうかを関数で調べる必要はありません。あなたは明示的にそれを明示的に閉じるだけです。

あなたはfoo2は、他のメソッドから呼ばれるようにしたい場合は、これらのメソッドは、接続を閉じる行う必要があります。

public void doSomething() { 
    MyClass myClass = new MyClass(); 
    try (Connection connection = createConnection()) { 
     myClass.foo2(connection); 
    } 
} 
関連する問題