Throwableをキャッチすることは悪い習慣ですか?


回答:


104

できるだけ具体的にする必要があります。そうでなければ、予期しないバグがこの方法で忍び寄る可能性があります。

その上、ThrowableカバーErrorも同様であり、それは通常リターンのポイントではありません。あなたはそれをキャッチ/処理したくない、あなたはそれを適切に修正することができるようにあなたのプログラムがすぐに死ぬようにしたいです。


38
エラーをキャッチして続行することが適切な場合があります。例:サーブレットで、特定のリクエストがたまたますべてのメモリを消費したためにOutOfMemoryErrorが発生した場合、リクエストの処理後にオブジェクトがGCになるため、続行を試みることができます。アサーションエラーについても同様です。リクエストで問題が発生したため、アプリケーションをシャットダウンしません。
ガウィ2013

7
OOMEの前に何が割り当てられ、何が割り当てられていなかったかをどのようにして知るのですか?TomcatやJBossのようなJ2EEコンテナの内部であっても、一度取得すればすべての賭けは無効になります。
bmauter 2013年

10
NoSuchMethodErrorが発生しましたが、展開の2週間後に発生したサーバーのシャットダウンによって、ありがたいことにすべてのお客様を排除することはできませんでした。すなわち。私たちは常にThrowableをキャッチし、エラーを処理して顧客に送信するために最善を尽くすキャッチオールを持っています。結局のところ、回復可能なエラーには多くの種類があり、1000人に1人の顧客にしか影響しない可能性があります。
ディーン・ヒラー2015年

10
" プログラムをすぐに終了させて​​、適切に修正できるようにする必要があります " =>プログラムが終了した場合、どのようにして何が起こったのかを知ることができますか?Throwable / Errorをキャッチして問題をログに記録するのは妥当なことです...
assylias

3
@assyliasスタンドアロンアプリケーションは、stderrに致命的なエラーをスローします。
フィリップホワイトハウス

36

これは悪い考えです。実際、捕まえることさえ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);
 }

4
+1は、例外をキャッチしてもダメだと述べています。少なくとも特別な注意が必要なThreadInterruptedExceptionがあります(要するに、それをキャッチした後、スレッドの中断ステータスを「true」に戻す必要があります)
Kirill Gamazkov

私はそれがあなたの言葉を説明するためだけのものであることを知っていますが、ユーザー入力が英数字または必要な形式であり、毎回どこでもtry catchを使用しない場合は、正規表現で確認できると思います。
amdev 2016年

キャッチできない場合にエラー/スロー可能オブジェクトがあるかどうかを知るにはどうすればよいですか?ログには何も表示されませんでした。Java EEアプリ。私がこの漁獲量を追加するまで、何が問題なのかわからないまま何日も過ごしました。
フィリップレゴ

2
オプション#2は悪い習慣だと思います。ログと再スローを使用した10の連鎖呼び出しを想像してください。ログファイルを見ると、満足できません。例外が10回記録されるため、ログが非常に読みにくくなります。私見ははるかに良いですthrow new Exception("Some additional info, eg. userId " + userId, e);。これは、10の原因を持つ1つの素晴らしい例外に記録されます。
PetrÚjezdský19年

21

またThrowable、をキャッチInterruptedExceptionすると、特別な扱いが必要なものもキャッチできることに注意してください。詳細については、InterruptedExceptionの処理を参照してください。

チェックされていない例外のみをキャッチしたい場合は、このパターンを検討することもできます

try {
   ...
} catch (RuntimeException exception) {
  //do something
} catch (Error error) {
  //do something
}

このようにして、コードを変更し、チェック例外をスローする可能性のあるメソッド呼び出しを追加すると、コンパイラーはそのことを通知し、この場合の対処法を決定できます。


14

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

13

メソッドから例外バブルを絶対に出せないのであれば、それは悪い習慣ではありません。

本当に例外を処理できない場合は、悪い習慣です。単にキャッチして再スローするよりも、メソッドシグネチャに「スロー」を追加する方が良いです。さらに悪いことに、それをRuntimeExceptionでラップして再スローすることもできます。


10
完全に同意しThrowableます- すべてのインスタンスを処理するための絶対に正当なケースがあります-たとえば、カスタム例外ロギングの場合。
Yuriy Nakonechnyy 2014

9

熱狂的にエラーをスローするライブラリを使用している場合は、Throwableのキャッチが必要になることがあります。そうしないと、ライブラリがアプリケーションを強制終了する可能性があります。

ただし、これらの状況では、すべてのThrowableではなく、ライブラリによってスローされた特定のエラーのみを指定するのが最善です。


12
または、より優れたライブラリを使用しますか?
Raedwald 2013年

6
確かに、もしあなたに選択肢があれば;-)
DNA

これは、投げる物を捕まえて投げ直す最大の問題です。スタックの上流にあるすべてのメソッドに対して、実際には不可能なインターフェースを作成します。これらは、スロー可能オブジェクトを処理する必要があるか、他のユーザーが処理しなければならない、使用できないスロー可能なスロー可能シグニチャーを持っている必要があります。
Andrew Norman

6

Throwableは、(例外だけでなく)スローできるすべてのクラスの基本クラスです。OutOfMemoryErrorまたはKernelErrorをキャッチした場合にできることはほとんどありません(java.lang.Errorをキャッチするタイミングを参照)。

例外をキャッチするだけで十分です。


5

それはあなたのロジックに依存するか、またはあなたのオプション/可能性により具体的です。意味のある方法で対応できる可能性のある特定の例外がある場合は、最初にそれをキャッチして実行することができます。

存在せず、すべての例外とエラーに対して同じことを行うと確信している場合(たとえば、エラーメッセージで終了する)、スロー可能オブジェクトをキャッチすることは問題ではありません。

通常、最初のケースが成立し、スロー可能オブジェクトをキャッチしません。しかし、それがうまく機能するケースはまだたくさんあります。


4

非常に悪い習慣として説明されていますが、まれに役立つだけでなく必須であるケースをません。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が実際にキャッシュおよび処理され。たとえば、次の検索ではtomcatstruts2および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


1
これらのリンクでコードを見ました。投げられるのは捕まったものだけではありません!Throwableの前にキャッチされた他の例外もあります。
developer1011

もちろん@ developer101ですが、彼らはキャッチしますthrowable、それがこの質問についてです
Alireza Fattahi

4

質問は少しあいまいです。「キャッチしても大丈夫ですThrowableか」、「Throwable何もしないでキャッチしても大丈夫ですか?」ここで多くの人が後者に答えましたが、それは副次的な問題です。あなたがキャッチされているかどうか、「消費」または例外を破棄してはならない時間の99%ThrowableまたはIOExceptionまたは何でも。

例外を伝播する場合、答えは(非常に多くの質問に対する答えのように)「依存する」です。それは、例外を使用して何をしているのか、なぜそれをキャッチしているのかによって異なります。

キャッチしたい理由の良い例Throwableは、エラーが発生した場合に何らかのクリーンアップを提供することです。たとえばJDBCでは、トランザクション中にエラーが発生した場合、トランザクションをロールバックする必要があります。

try {
  
} catch(final Throwable throwable) {
  connection.rollback();
  throw throwable;
}

例外は破棄されず、伝播されることに注意してください。

しかし、一般的なポリシーとして、Throwable理由がなく、どの特定の例外がスローされているかを確認するのが面倒なので、キャッチすることは、形が悪く、悪い考えです。


1

一般的に言えば、Errors をキャッチしたくないのですが、(少なくとも)2つの特定のケースが適切であると考えることができます。

  • 特にエラーに応じてアプリケーションをシャットダウンしたい AssertionError 無害な。
  • ExecutorService.submit()に似たスレッドプーリングメカニズムを実装していますか?例外をユーザーに転送して、ユーザーが例外を処理できるようにする必要があります。

0

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)

0

Throwableは、すべてのエラーと例外のスーパークラスです。catch句でThrowableを使用すると、すべての例外をキャッチするだけでなく、すべてのエラーもキャッチします。エラーはJVMによってスローされ、アプリケーションによる処理を意図していない重大な問題を示します。その典型的な例は、OutOfMemoryErrorまたはStackOverflowErrorです。どちらも、アプリケーションの制御外にあり、処理できない状況が原因です。したがって、Throwableの内部にのみ例外が存在することを確信している場合を除き、Throwableをキャッチしないでください。


-1

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されます。キャッチされ、例外がログに記録されるだけで、残りのフローを続行できます。


私は、メールを送信するジョブ(キュー付き)専用のスレッドを用意することで、これを回避しようとしています。
boumbh 2015年

これはまだ悪いコードであることをお勧めします。Exception必ずsをキャッチしてくださいThrowable
アンドリューフ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.