あなたの質問にはかなり困惑しています。あなたが理解していないJava例外/例外処理について明らかに何かがあります。それでは、最初から始めましょう。
Java では、すべての例外 (この用語が Java 言語仕様で使用されているという意味で) は、 のサブクラスである何らかのクラスのインスタンスですjava.lang.Throwable
。Throwable の直接のサブクラスは 2 つ (2 つだけ) あります。すなわちjava.lang.Exception
とjava.lang.Error
. これらすべてのクラスのインスタンス ... Throwable および Error のインスタンスを含む ... は、JLS では例外と呼ばれます。
例外ハンドラーは、catch
宣言で使用される例外タイプと互換性のある割り当てである (JLS の意味での) 例外をキャッチします。たとえば、次のようになります。
try {
....
} catch (Exception ex) {
...
}
try
のインスタンスであるjava.lang.Exception
か、直接または間接のサブタイプであるブロックでスローされた例外をキャッチしますjava.lang.Exception
。java.lang.Throwable
しかし、それは(明らかに)上記のいずれでもないため、 のインスタンスをキャッチしません。
一方で:
try {
....
} catch (Throwable ex) {
...
}
のインスタンスをキャッチしますjava.lang.Throwable
。
これに照らして例を確認すると、f
メソッドが Throwable インスタンスをキャッチしていない理由は明らかです。catch 句の例外タイプと一致しません! 対照的に、このg
メソッドでは、Exception インスタンスが catch 句の例外タイプと一致したため、キャッチされます。
Throwable を にスローする必要があることについて、あなたが何を言っているのかわかりませんg
。まず、メソッドが Throwable をスローすると宣言しているという事実は、実際にそれをスローする必要があるという意味ではありません。それが言っているのは、Throwable に割り当て可能な何かをスローする可能性があるということだけです...おそらくメソッドの将来のバージョンでg
。throw e;
次に、外側の catch ブロックに追加すると、 Throwable に割り当て可能なものをスローすることになります。
最後に、一般的に、Throwable、Exception、Error、および RuntimeException のインスタンスを作成することはお勧めできません。そして、いつ、どのように捕まえるかには細心の注意を払う必要があります。例えば:
try {
// throws an IOException if file is missing
InputStream is = new FileInputStream("someFile.txt");
// do other stuff
} catch (Exception ex) {
System.err.println("File not found");
// WRONG!!! We might have caught some completely unrelated exception;
// e.g. a NullPointerException, StackOverflowError,
}
編集- OPのコメントに応じて:
しかし、 throw e.fillInStackTrace(); でスローするもの 例外ではなく、Throwable のインスタンスである必要があります。
Javadoc は、返されたオブジェクトが、メソッドを呼び出している例外オブジェクトであることを明確に示しています。このメソッドの目的はfillInStacktrace()
、既存のオブジェクトのスタック トレースを埋めることです。別の例外が必要な場合は、 を使用new
して作成する必要があります。
実際には、外側の例外ハンドラは、throw e.fillInStackTrace() によってスローされた Throwable をキャッチしてはならないということです。
その理由を説明しました-Throwableは実際には元の例外であるためです。私の説明について、あなたが理解できない何かがありますか、それとも単に Java の定義方法が気に入らないと言っているのですか?
編集2
また、外部例外ハンドラーが Throwable 例外を処理できる場合、メソッド g が Throwable 例外をスローするように指定する必要があるのはなぜですか
あなたは私が言ったことを誤解しています...それは、例外をスローした場合、throws Throwable
冗長ではないということでした。OTOHさん、ようやくあなたの不満を理解できたと思います。
あなたの苦情の核心は、これでコンパイルエラーが発生することだと思います:
public void function() throws Exception {
try {
throw new Exception();
} catch (Exception ex) {
throw ex.fillInStackTrace();
// according to the static type checker, the above throws a Throwable
// which has to be caught, or declared as thrown. But we "know" that the
// exception cannot be anything other than an Exception.
}
}
これはやや予想外であることがわかります。しかし、それは避けられないのではないかと心配しています。fillInStacktrace
すべての場合に機能する の署名を宣言できる方法はありません (Java の型システムへの大幅な変更を除く) 。たとえば、メソッドの宣言を Exception クラスに移動した場合、Exception のサブタイプで同じ問題が繰り返されるだけです。ただし、ジェネリック型パラメーターを使用してシグネチャを表現しようとすると、Throwable の明示的なジェネリック型のすべてのサブクラスを作成する必要があります。
幸いなことに、治療法は非常に簡単です。fillInStacktrace()
の結果を次のようにキャストします。
public void function() throws Exception {
try {
throw new Exception();
} catch (Exception ex) {
throw (Exception) (ex.fillInStackTrace());
}
}
そして最後のポイントは、アプリケーションが明示的に を呼び出すことは非常に珍しいということですfillInStacktrace()
。このことを考えると、Java 設計者がこれを解決しようとして「腹をくくった」ことには、まったく価値がありませんでした。特に、それは本当に些細な不便にすぎないので... せいぜい。