私のクラスに、リソースを取得するメソッド start() とリソースを解放する stop() があるとします。クラスの開始メソッドは、メンバー オブジェクトの start() メソッドを呼び出すことができます。メンバー オブジェクトの 1 つの start() が例外をスローした場合、start() が成功したすべてのメンバー オブジェクトに対して stop() が呼び出されるようにする必要があります。
class X {
public X ()
{
a = new A();
b = new B();
c = new C();
d = new D();
}
public void start () throws Exception
{
try {
a.start();
} catch (Exception e) {
throw e;
}
try {
b.start();
} catch (Exception e) {
a.stop();
throw e;
}
try {
c.start();
} catch (Exception e) {
b.stop();
a.stop();
throw e;
}
try {
d.start();
} catch (Exception e) {
c.stop();
b.stop();
a.stop();
throw e;
}
}
public void stop ()
{
d.stop();
c.stop();
b.stop();
a.stop();
}
private A a;
private B b;
private C c;
private D d;
}
クリーンアップ コードの 2 次成長に注意してください。クリーンアップを行うための最良の方法 (コード量が最小) は何ですか? CI では、関数の下部にあるクリーンアップ コードと "goto" を使用して適切な場所にジャンプすることでこれを簡単に実行できますが、Java には goto がありません。start() されていないオブジェクトで stop() を呼び出すことは許可されていないことに注意してください。上記とまったく同じですが、より短いコードを探しています。
これまでのところ、私がたどり着いた唯一の解決策は、次のように、ブール値を使用して何が開始されたかを記憶することです。
public void start () throws Exception
{
boolean aStarted = false;
boolean bStarted = false;
boolean cStarted = false;
boolean dStarted = false;
try {
a.start();
aStarted = true;
b.start();
bStarted = true;
c.start();
cStarted = true;
d.start();
dStarted = true;
} catch (Exception e) {
if (dStarted) d.stop();
if (cStarted) c.stop();
if (bStarted) b.stop();
if (aStarted) a.stop();
throw e;
}
}
「finally」と「try-with-resources」については知っていますが、例外がなければリソースを解放すべきではないため、ここではどちらも当てはまらないようです。
PS これは、私の例外の使用やプログラムの設計に関する質問ではありません。これは特に、初期化コードでエラーが発生した場合のクリーンアップに関するものです。