例外のコレクションを根本原因として渡すにはどうすればよいですか?


52

一部のメソッドはmyMethod、いくつかの並列実行を呼び出し、それらの終了を待ちます。

これらの並列実行は、例外で終了する可能性があります。したがってmyMethod、例外リストを取得します。

例外リストを根本原因として渡したいのですが、根本原因は単一の例外にすぎない場合があります。確かに私は自分の例外を作成して私が望むものを達成できますが、Java、Spring、またはSpring Batchにこのようなものがすぐに使えるかどうかを知りたいです。


3
.NETには、AggregateException例外のリストを含むがあります。そのアイデアはJavaにも適用できるはずです。
usr

回答:


49

私はそれを行うかどうかはわかりませんが(JavaDocを考えると、私が躊躇する理由を伝えることができませんでした)、抑制された例外のリストがにあり、Throwableを介してに追加できますaddSuppressed。JavaDocは、これがJVMがtry-with-resourcesで使用するためだけであるとは言っていないようです。

この例外を配信するために抑制された例外に、指定された例外を追加します。このメソッドはスレッドセーフであり、通常、try-with-resourcesステートメントによって(自動的かつ暗黙的に)呼び出されます。

抑制動作は、コンストラクタで無効にしない限り有効です。抑制が無効になっている場合、このメソッドは引数を検証する以外に何もしません。

1つの例外によって別の例外が発生すると、通常、最初の例外がキャッチされ、次に2番目の例外がスローされます。つまり、2つの例外の間には因果関係があります。対照的に、兄弟コードブロックで2つの独立した例外がスローされる状況があります。特に、try-with-resourcesステートメントのtryブロックと、リソースを閉じるコンパイラが生成したfinallyブロックでは例外が発生します。これらの状況では、スローされた例外の1つだけが伝播されます。try-with-resourcesステートメントでは、そのような例外が2つある場合、tryブロックから発生した例外が伝播され、finallyブロックからの例外が、tryブロックからの例外によって抑制された例外のリストに追加されます。例外がスタックをほどくと、

例外が例外を抑制している一方で、別の例外が原因である可能性があります。例外が他の例外を抑制するかどうかとは異なり、例外がスローされた後にのみ決定されるかどうかとは異なり、例外が原因を持っているかどうかは、その作成時に意味的にわかります。

プログラマーが記述したコードは、複数の兄弟例外があり、1つしか伝搬できない状況でこのメソッドを呼び出すことを利用することもできます。

あなたのケースに合っているように見える最後の段落に注意してください。


[...]例外が他の例外を抑制するかどうかは[...]通常、例外がスローされた後にのみ決定されます。複数の抑制された例外が並列実行から収集される場合、これは当てはまらないと思います。
GOTO 0

24

例外とその原因は常に1対1のものです。1つの例外をスローすることができ、各例外は1つの原因のみを持つことができます(これも1つの原因を持つことができます...)。

これは、特に説明したようにマルチスレッドの動作を検討する場合、設計上の欠陥と考えることができます。

これがJava 7 addSuppressedがスロー可能オブジェクトに追加された理由の1つであり、基本的に他の1つの例外に任意の量の例外をアタッチできます(他の主な動機は、リソースを試して、サイレントにドロップせずに最後のブロックで例外を処理する方法が必要でしたそれら)。

したがって、基本的には、プロセスが失敗する原因となる例外が1つある場合は、その例外を上位レベルの例外の原因として追加し、さらに例外がある場合は、を使用してそれらを元の例外に追加しaddSuppressedます。その考えは、その最初の例外が、他の人が「実際の例外チェーン」のメンバーになることを「抑制」したというものです。

サンプルコード:

Exception exception = null;
for (Foobar foobar : foobars) {
  try {
    foobar.frobnicate();
  } catch (Exception ex) {
    if (exception == null) {
      exception = ex;
    } else {
      exception.addSuppressed(ex);
    }
  }
}
if (exception != null) {
  throw new SomethingWentWrongException(exception);
}

4
根本的な例外の1つが「メイン」の例外として本当に特定できない限り、私はあなたが提案する方法でそれを完全には行いません。例外の1つをメインの例外として任意に選択し、他の例外を抑制として選択した場合、抑制された例外を無視してメインの例外を報告するように呼び出し側を招待します。「メイン」の例外がTypoInUserInputExceptionであり、抑制されたものはDatabaseCorruptedExceptionです。
Ilmari Karonen

1
...その代わり、私はマークしたいすべての SomethingWentWrongExceptionによって抑制として根本的な例外を、その例外を明確に一つ以上の抑制の例外があることを示すメッセージ与える必要があります」のように従って、例えば何かXのうちYの下の障害のリストを表示、タスクが失敗しました」
Ilmari Karonen
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.