どのような状況でアプリケーションでJava.lang.Error
をキャッチする必要がありますか?
通常、決して。ただし、特定のエラーをキャッチする必要がある場合があります。
フレームワークのようなコードを書いている場合(サードパーティのクラスを読み込む)、LinkageErrorsをキャッチするのが賢明かもしれません(クラス定義が見つからない、リンクが満たされていない、互換性のないクラスの変更)。また、エラーのサブクラスを投げる愚かなサードパーティのコードを見てきましたので、これらのいずれかを処理する必要があります。
ところで、OutOfMemoryから回復できないかどうかはわかりません。
決して。アプリケーションが次のコード行を実行できることを決して確信できません。 OutOfMemoryError
を取得した場合、 信頼性の高い処理ができるという保証はありません になります。 RuntimeExceptionとチェック済み例外をキャッチしますが、エラーは発生しません。
通常、Java.lang.Error
を常にキャッチしてログに書き込むか、ユーザーに表示する必要があります。私はサポートで働いており、プログラマーがプログラムで何が起こったのかを知ることができないことを毎日見ています。
デーモンスレッドがある場合は、終了しないようにする必要があります。それ以外の場合、アプリケーションは正しく動作します。
Java.lang.Error
は最高レベルでのみキャッチする必要があります。
エラーのリストを見ると、ほとんどを処理できることがわかります。たとえば、破損したZipファイルの読み取り時にZipError
が発生します。
最も一般的なエラーはOutOfMemoryError
とNoClassDefFoundError
であり、これらはほとんどの場合ランタイムの問題です。
例えば:
int length = Integer.parseInt(xyz);
byte[] buffer = new byte[length];
OutOfMemoryError
を生成できますが、これは実行時の問題であり、プログラムを終了する理由はありません。
NoClassDefFoundError
は、ライブラリが存在しない場合、または別のJavaバージョンを使用している場合にほとんど発生します。プログラムのオプション部分である場合は、プログラムを終了しないでください。
Throwable
をトップレベルでキャッチし、有用なエラーメッセージを生成するのが良い考えである理由について、さらに多くの例を挙げることができます。
マルチスレッド環境では、ほとんどの場合、それをキャッチしたいです!キャッチしたら、ログに記録し、アプリケーション全体を終了します!そうしないと、いくつかの重要な部分を実行している可能性のあるスレッドが死んでしまい、アプリケーションの残りの部分はすべてが正常であると考えます。その中から、多くの望ましくない状況が発生する可能性があります。 1つの最小の問題は、1つのスレッドが機能していないために他のスレッドがいくつかの例外をスローし始めた場合、問題の根本を簡単に見つけることができないことです。
たとえば、通常、ループは次のようになります。
try {
while (shouldRun()) {
doSomething();
}
}
catch (Throwable t) {
log(t);
stop();
System.exit(1);
}
場合によっては、さまざまなエラーを異なる方法で処理する必要があります。たとえば、OutOfMemoryErrorでは、アプリケーションを定期的に閉じることができます(メモリを解放して続行することもできます)。
めったにありません。
私は、スレッドのトップレベルでのみ言って、スレッドが死んだ理由を示すメッセージを発行しようと試みます。
このようなことを行うフレームワークを使用している場合は、フレームワークに任せてください。
ほとんどは決してない。エラーは、アプリケーションが通常は何もできない問題になるように設計されています。唯一の例外はエラーの表示を処理することかもしれませんが、それでもエラーによっては計画どおりに進まない場合があります。
Error
は通常、キャッチされるべきではありません。これは発生しないはずの異常な状態を示します。
Error
クラスのJava API仕様から:
Error
は、Throwable
のサブクラスであり、合理的なアプリケーションがキャッチしようとしてはならない重大な問題を示します。そのようなエラーのほとんどは異常な状態です。 [...]メソッドは、メソッドの実行中にスローされるがキャッチされない可能性のあるエラーのサブクラスをthrows句で宣言する必要はありません。これらのエラーは決して発生しない異常な状態であるためです。
仕様に記載されているように、Error
は、Error
が発生したときにアプリケーションが実行できることがほとんどない状況でのみスローされ、状況によっては、Java仮想マシン自体が不安定になる可能性があります状態( VirtualMachineError
など)
Error
はThrowable
のサブクラスですが、これはtry-catch
句でキャッチできますが、Error
がJVMによってスローされるとアプリケーションが異常な状態になるため、おそらく実際には必要ありません。
Java言語仕様、第2版 のセクション 11.5例外階層 にも、このトピックに関する短いセクションがあります。
新しい単体テストフレームワークを作成することに夢中になっている場合、テストランナーは、おそらくテストケースによってスローされたJava.lang.AssertionErrorをキャッチする必要があります。
それ以外の場合は、他の回答を参照してください。
また、エラーをキャッチした場合、を再スローする必要がある他のいくつかのケースがあります 。たとえば、 ThreadDeath は決してキャッチされるべきではありません。含まれる環境(アプリケーションサーバーなど)でキャッチすると大きな問題を引き起こす可能性があります。
アプリケーションは、非同期で終了した後にクリーンアップする必要がある場合にのみ、このクラスのインスタンスをキャッチする必要があります。 ThreadDeathがメソッドにキャッチされた場合、スレッドが実際に停止するように再スローすることが重要です。
非常に、めったにありません。
私は、非常に具体的な既知の1つのケースに対してのみそれを行いました。たとえば、2つのindependence ClassLoaderが同じDLLをロードすると、Java.lang.UnsatisfiedLinkErrorがスローされる可能性があります。 (JARを共有クラスローダーに移動することに同意します)
しかし、最も一般的なケースは、ユーザーが苦情を申し立てたときに何が起こったのかを知るためにロギングが必要だったことです。静かに死んでしまうのではなく、ユーザーにメッセージやポップアップが必要です。
C/C++のプログラマでさえ、エラーをポップし、終了する前に人々が理解できないことを伝えます(メモリ障害など)。
テスト環境でJava.lang.AssertionErrorをキャッチすると非常に便利です...
Androidアプリケーションでは、 Java.lang.VerifyError をキャッチしています。私が使用しているライブラリは、古いバージョンのOSを搭載したデバイスでは機能せず、ライブラリコードはこのようなエラーをスローします。もちろん、実行時にOSのバージョンをチェックすることでエラーを回避できましたが、
理想的には、エラーを処理/キャッチすべきではありません。ただし、フレームワークまたはアプリケーションの要件に基づいて、行う必要がある場合があります。たとえば、より多くのメモリを消費するDOM Parserを実装するXML Parserデーモンがあるとします。 OutOfMemoryErrorになったときにパーサースレッドを停止する必要がないなどの要件がある場合は、代わりにそれを処理し、アプリケーション/フレームワークの管理者にメッセージ/メールを送信する必要があります。
JVMが期待どおりに動作しなくなった場合、またはエラーが発生した場合、エラーが発生します。エラーをキャッチした場合、catchブロックが実行されるという保証はなく、最後まで実行されるという保証はありません。
また、実行中のコンピューター、現在のメモリの状態にも依存するため、テスト、試行、および最善を尽くす方法はありません。あなただけの結果があります。
また、コードの可読性をダウングレードします。
理想的には、異常な状態であるため、Javaアプリケーションでエラーをキャッチしないでください。アプリケーションは異常な状態になり、カーッシングまたは重大な誤った結果をもたらす可能性があります。
アサーションが行われたことを確認する単体テスト内でエラーをキャッチすることが適切な場合があります。誰かがアサーションを無効にするか、そうでなければあなたが知りたいアサーションを削除する場合