回答:
できるだけ具体的にする必要があります。そうでなければ、予期しないバグがこの方法で忍び寄る可能性があります。
その上、Throwable
カバーError
も同様であり、それは通常リターンのポイントではありません。あなたはそれをキャッチ/処理したくない、あなたはそれを適切に修正することができるようにあなたのプログラムがすぐに死ぬようにしたいです。
これは悪い考えです。実際、捕まえることさえException
通常は悪い考えです。例を考えてみましょう:
try {
inputNumber = NumberFormat.getInstance().formatNumber( getUserInput() );
} catch(Throwable e) {
inputNumber = 10; //Default, user did not enter valid number
}
ここで、しばらくの間getUserInput()がブロックし、別のスレッドがスレッドを可能な限り最悪の方法で停止したとします(thread.stop()を呼び出します)。あなたのキャッチブロックは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);
}
throw new Exception("Some additional info, eg. userId " + userId, e);
。これは、10の原因を持つ1つの素晴らしい例外に記録されます。
またThrowable
、をキャッチInterruptedException
すると、特別な扱いが必要なものもキャッチできることに注意してください。詳細については、InterruptedExceptionの処理を参照してください。
チェックされていない例外のみをキャッチしたい場合は、このパターンを検討することもできます
try {
...
} catch (RuntimeException exception) {
//do something
} catch (Error error) {
//do something
}
このようにして、コードを変更し、チェック例外をスローする可能性のあるメソッド呼び出しを追加すると、コンパイラーはそのことを通知し、この場合の対処法を決定できます。
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
ます- すべてのインスタンスを処理するための絶対に正当なケースがあります-たとえば、カスタム例外ロギングの場合。
熱狂的にエラーをスローするライブラリを使用している場合は、Throwableのキャッチが必要になることがあります。そうしないと、ライブラリがアプリケーションを強制終了する可能性があります。
ただし、これらの状況では、すべてのThrowableではなく、ライブラリによってスローされた特定のエラーのみを指定するのが最善です。
Throwableは、(例外だけでなく)スローできるすべてのクラスの基本クラスです。OutOfMemoryErrorまたはKernelErrorをキャッチした場合にできることはほとんどありません(java.lang.Errorをキャッチするタイミングを参照)。
例外をキャッチするだけで十分です。
それはあなたのロジックに依存するか、またはあなたのオプション/可能性により具体的です。意味のある方法で対応できる可能性のある特定の例外がある場合は、最初にそれをキャッチして実行することができます。
存在せず、すべての例外とエラーに対して同じことを行うと確信している場合(たとえば、エラーメッセージで終了する)、スロー可能オブジェクトをキャッチすることは問題ではありません。
通常、最初のケースが成立し、スロー可能オブジェクトをキャッチしません。しかし、それがうまく機能するケースはまだたくさんあります。
非常に悪い習慣として説明されていますが、まれに役立つだけでなく必須であるケースをません。2つの例を示します。
ユーザーに意味のある完全なエラーページを表示する必要があるWebアプリケーション。このコードは、try/catch
すべてのリクエストハンドラ(サーブレット、Strutsアクション、または任意のコントローラ....)の周囲にあるため、これが発生することを確認します。
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);
}
しかし、例外が発生するとどうなりますか?1回の転送が成功した場合とそうでない場合があるので、停止しないでください。すべてのユーザーを続行し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/search?utf8=%E2%9C%93&q=catch%28Throwable https://github.com/apache/struts/search?utf8=%E2%9C%93&q=catch %28Throwable https://github.com/primefaces/primefaces/search?utf8=%E2%9C%93&q=catch%28Throwable
throwable
、それがこの質問についてです
質問は少しあいまいです。「キャッチしても大丈夫ですThrowable
か」、「Throwable
何もしないでキャッチしても大丈夫ですか?」ここで多くの人が後者に答えましたが、それは副次的な問題です。あなたがキャッチされているかどうか、「消費」または例外を破棄してはならない時間の99%Throwable
またはIOException
または何でも。
例外を伝播する場合、答えは(非常に多くの質問に対する答えのように)「依存する」です。それは、例外を使用して何をしているのか、なぜそれをキャッチしているのかによって異なります。
キャッチしたい理由の良い例Throwable
は、エラーが発生した場合に何らかのクリーンアップを提供することです。たとえばJDBCでは、トランザクション中にエラーが発生した場合、トランザクションをロールバックする必要があります。
try {
…
} catch(final Throwable throwable) {
connection.rollback();
throw throwable;
}
例外は破棄されず、伝播されることに注意してください。
しかし、一般的なポリシーとして、Throwable
理由がなく、どの特定の例外がスローされているかを確認するのが面倒なので、キャッチすることは、形が悪く、悪い考えです。
一般的に言えば、Error
s をキャッチしたくないのですが、(少なくとも)2つの特定のケースが適切であると考えることができます。
AssertionError
無害な。throwableを使用すると、Errorもカバーされます。
例。
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またはStackOverflowErrorです。どちらも、アプリケーションの制御外にあり、処理できない状況が原因です。したがって、Throwableの内部にのみ例外が存在することを確信している場合を除き、Throwableをキャッチしないでください。
Throwableをキャッチすることは一般に悪い習慣ですが(この質問に関する多数の回答で説明されているように)、 Throwable
が役立つは非常に一般的です。私が仕事で使用するそのようなケースの1つを、簡単な例で説明しましょう。
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つのInteger値の合計に関係しているだけだからです。したがって、電子メールアラートをディスパッチするコードはtry-catch
ブロックに配置され、ブロックThrowable
されます。キャッチされ、例外がログに記録されるだけで、残りのフローを続行できます。
Exception
必ずsをキャッチしてくださいThrowable
。