Throwable をキャッチするのは悪い習慣ですか?
-
08-09-2020 - |
質問
捕まえるのは悪い習慣ですか? Throwable
?
たとえば次のようなものです。
try {
// Some code
} catch(Throwable e) {
// handle the exception
}
これは悪い習慣ですか? それともできるだけ具体的にする必要がありますか?
解決
できるだけ具体的にする必要があります。それ以外の場合は、このように予期せぬバグが不要になる可能性があります。
その上、 Throwable
カバーError
その通常Returnのポイント。あなたはそれをキャッチ/ハンドルしたくない、あなたはあなたのプログラムがすぐに死ぬことを望むようにあなたがそれを正しく修正することができます。
他のヒント
これは悪い考えです。実際、キャッチしても Exception
通常は悪い考えです。例を考えてみましょう。
try {
inputNumber = NumberFormat.getInstance().formatNumber( getUserInput() );
} catch(Throwable e) {
inputNumber = 10; //Default, user did not enter valid number
}
ここで、 getUserInput() がしばらくブロックし、別のスレッドが最悪の方法でスレッドを停止したとします ( thread.stop() を呼び出します)。catch ブロックは、 ThreadDeath
エラー。これは超最悪です。その例外をキャッチした後のコードの動作は、ほとんどが未定義です。
例外をキャッチする場合にも同様の問題が発生します。多分 getUserInput()
InterruptException、結果をログに記録しようとしたときのアクセス許可拒否例外、またはその他のあらゆる種類の失敗が原因で失敗しました。何が問題だったのか全く分かりません。そのため、問題を解決する方法も分かりません。
より良い選択肢が 3 つあります。
1 -- 処理方法がわかっている例外を正確にキャッチします。
try {
inputNumber = NumberFormat.getInstance().formatNumber( getUserInput() );
} catch(ParseException e) {
inputNumber = 10; //Default, user did not enter valid number
}
2 -- 発生した例外の処理方法がわからない場合は、再スローします。
try {
doSomethingMysterious();
} catch(Exception e) {
log.error("Oh man, something bad and mysterious happened",e);
throw e;
}
3 -- 再スローすることを忘れないようにするため、finally ブロックを使用します。
Resources r = null;
try {
r = allocateSomeResources();
doSomething(r);
} finally {
if(r!=null) cleanUpResources(r);
}
Throwable
をキャッチすると、特別な処理が必要なInterruptedException
をキャッチすることもできます。詳細については、詳細については
このように、コードを変更してチェックされた例外をスローできるメソッド呼び出しを追加すると、コンパイラはそれを思い出させ、次にこの場合に何をすべきかを決めることができます。
ErrorクラスのJavadoc(これらをキャッチしないことをお勧めします)から直線:
* An <code>Error</code> is a subclass of <code>Throwable</code>
* that indicates serious problems that a reasonable application
* should not try to catch. Most such errors are abnormal conditions.
* The <code>ThreadDeath</code> error, though a "normal" condition,
* is also a subclass of <code>Error</code> because most applications
* should not try to catch it.
* A method is not required to declare in its <code>throws</code>
* clause any subclasses of <code>Error</code> that might be thrown
* during the execution of the method but not caught, since these
* errors are abnormal conditions that should never occur.
*
* @author Frank Yellin
* @version %I%, %G%
* @see java.lang.ThreadDeath
* @since JDK1.0
. メソッドから絶対に例外バブルを持つことができない場合は悪い練習ではありません。
本当に例外を処理できない場合は悪い練習です。ただキャッチして再投入するだけでなく、runtimeExceptionでそれを包み込み、再スローするよりも、メソッドシグネチャに "スロー"を追加する方が良い。
キャッチは、熱心に熱心にエラーを投げるライブラリを使用している場合に必要な場合があります。それ以外の場合は、ライブラリがアプリケーションを殺す可能性があります。
しかし、このような状況下では、すべてのスローラよりもむしろライブラリによってスローされた特定のエラーのみを指定することが最善です。
throwableは、スローされることができるよりもすべてのクラスの基本クラスです(例外だけでなく)。OutOfMemoryErrorまたはKernelErrorをキャッチする場合はほとんどできません( Javaをキャッチするときlang.error?)
引用例外は十分であるべきです。
それはあなたの論理によって異なります、あるいはあなたのオプション/可能性に具体的になるようになります。意味のある方法でおそらく反応できる特定の例外がある場合は、最初にキャッチすることができ、そうすることができます。
がいない場合、あなたはスローブールをキャッチすることが問題ではない以外のすべての例外とエラー(例えばエラーメッセージで終了)に対して同じことをするでしょう。
通常最初のケースが保持し、あなたはスロー可能なものを捕まえないでしょう。しかし、それをキャッチすることがうまくいくケースがまだありません。
それは非常に悪い練習として説明されていますが、それが有用であるだけでなく、 ream ケースも見つけるかもしれません。ここには2つの例があります。
Webアプリケーションでは、ユーザーに完全なエラーページを表示する必要があります。
このコードは、これが起こることを確認してください。これが、すべてのリクエスト済みの登録者(サーブレット、Struts Actions、または任意のコントローラ...)の周りの大きなtry/catch
であるため、
try{
//run the code which handles user request.
}catch(Throwable ex){
LOG.error("Exception was thrown: {}", ex);
//redirect request to a error page.
}
.
}
別の例として、資金譲渡事業を提供するサービスクラスがあると考えています。このメソッドは、転送が行われた場合はTransferReceipt
を返し、それができなかった場合にはNULL
を返します。
String FoundtransferService.doTransfer( fundtransferVO);
.
今すぐイメージングあなたはユーザーからのファンド転送のList
を取得し、それらをすべてするために上記のサービスを使用する必要があります。
for(FundTransferVO fundTransferVO : fundTransferVOList){
FoundtransferService.doTransfer( foundtransferVO);
}
.
しかし、 例外が発生した場合、どうなるでしょうか。一方の転送が成功した可能性があるため、すべてのユーザーList
を介して進行し続け、結果を各転送に表示する必要があります。だからあなたはこのコードに終わります。
for(FundTransferVO fundTransferVO : fundTransferVOList){
FoundtransferService.doTransfer( foundtransferVO);
}catch(Throwable ex){
LOG.error("The transfer for {} failed due the error {}", foundtransferVO, ex);
}
}
.
throwable
が本当にキャッシュされて処理されていることを確認するために、たくさんのオープンソースプロジェクトを閲覧できます。たとえば、ここではtomcat
、struts2
とprimefaces
の検索です。
https://github.com/ Apache / Tomcat /検索?UTF8=%E2%9C%93&AMP; Q= CATCH%28THROWABLE https://github.com/apache/struts. /検索?UTF8=%E2%9C%93&AMP; Q= CATCH%28THROWABLE https://github.com/primefaces/primefaces. /検索?UTF8=%E2%9C%93&AMP; Q=キャッチ%28ThRowable
質問は少し曖昧です。 「Throwable
をキャッチするのは大丈夫です」、または「Throwable
をキャッチして何もしない」と尋ねていますか?ここで多くの人が後者に答えたが、それは副題です。 99%の時間の範囲ではないか、または例外を破棄しないでください。
例外を伝播した場合、答え(たくさんの質問に対する答えのように)は「それは依存します」です。それはあなたが例外で行っているのかによって異なります - なぜあなたはそれをキャッチしているのです。
Throwable
をキャッチしたい理由の良い例は、エラーがある場合はある種のクリーンアップを提供することです。たとえば、JDBCでは、トランザクション中にエラーが発生した場合は、トランザクションをロールバックしたいと思います。
try {
…
} catch(final Throwable throwable) {
connection.rollback();
throw throwable;
}
.
例外は破棄されていないが伝播されていることに注意してください。
一般的な方針として、あなたが理由がないのでIOException
をキャッチし、どの特定の例外がスローされているかを確認するのが遅すぎるのですが、劣った形や悪い考えです。
一般的に言えば、捕まえるのは避けたいですよね Error
ただし、そうするのが適切な具体的なケースが (少なくとも) 2 つ考えられます。
- 特にエラーに応じてアプリケーションをシャットダウンしたい場合
AssertionError
それ以外の場合は無害です。 - 次のようなスレッド プーリング メカニズムを実装していますか? ExecutorService.submit() そのためには、ユーザーが例外を処理できるように、例外をユーザーに転送する必要があります。
Throwable を使用している場合、エラーもカバーしていて、それはそれです。
例
public class ExceptionTest {
/**
* @param args
*/
public static void m1() {
int i = 10;
int j = 0;
try {
int k = i / j;
System.out.println(k);
} catch (Throwable th) {
th.printStackTrace();
}
}
public static void main(String[] args) {
m1();
}
.
}
出力:
java.lang.ArithmeticException: / by zero
at com.infy.test.ExceptionTest.m1(ExceptionTest.java:12)
at com.infy.test.ExceptionTest.main(ExceptionTest.java:25)
. Throwableはすべてのエラーとエクササイズのスーパークラスです。 Catch句にThrowableを使用している場合は、すべての例外をキャッチするだけでなく、すべてのエラーを獲得します。アプリケーションによって処理されることを意図しない深刻な問題を示すために、エラーがJVMによってスローされます。そのための一般的な例は、OutOfMemoryErrorまたはStackOverFlowRorです。どちらもアプリケーションの管理の外側にある状況によって引き起こされ、処理できません。それで、あなたがスローブールの内側に例外存在するだけであることがわかっていると確信していない限り、あなたはかなり自信を持っていない限りキャッチするべきではありません。
この質問に対する多数の答えによって説明されているように(数多くの回答によって解明されたように)、一般的には悪い練習である。私の仕事で使っているそのような場合は、簡単な例を持って説明しましょう。
2つの数字を追加した方法を考慮し、成功した後、特定の人に電子メールアラートを送信します。返される数が重要で、呼び出し方法によって使用されていると仮定します。
public Integer addNumbers(Integer a, Integer b) {
Integer c = a + b; //This will throw a NullPointerException if either
//a or b are set to a null value by the
//calling method
successfulAdditionAlert(c);
return c;
}
private void successfulAdditionAlert(Integer c) {
try {
//Code here to read configurations and send email alerts.
} catch (Throwable e) {
//Code to log any exception that occurs during email dispatch
}
}
.
電子メール警告を送信するためのコードは、多くのシステム構成を読み取り、したがって、そのコードブロックからスローされるさまざまな例外がある可能性があります。しかし、それが提供する2つの整数値の合計に単純に関係しているので、アラートディスパッチ中にアラートディスパッチ中に遭遇する例外が発生したくない。したがって、電子メールアラートをディスパッチするためのコードは、Throwable
ブロックに配置されます。ここでは、try-catch
が捕捉され、一度の例外がログに記録され、残りのフローを続行できます。