web-dev-qa-db-ja.com

なぜCatch(Exception)はほとんど常に悪いアイデアなのですか?

なぜcatch(Exception)がほとんどの場合悪い考えなのですか?

62
Nasser Hadjloo

例外をキャッチすると適切に処理するはずですだからです。また、コード内であらゆる種類の例外を処理することは期待できません。また、すべての例外をキャッチすると、処理できない例外が発生し、スタックの上位にあるコードが適切に処理できないようになる可能性があります。

一般的な原則は、できるだけ具体的なタイプをキャッチすることです。

57
anthares

短編:バグマスキングと呼ばれます。うまく機能せず例外をスローしているコードがある場合(またはそのコードに不正な入力を渡した場合)、起こり得るすべての例外をキャッチするだけで目がくらむと、実際にバグを発見して修正することはできません。

18
dimitarvp

例外を適切に処理できる場合にのみ、例外をキャッチする必要があります。すべての可能な例外を適切に処理できないため、それらをキャッチしないでください:-)

8
Darin Dimitrov

例外が発生した理由が本当にわからないため、OutOfMemoryExceptionや同様の低レベルのシステム例外など、いくつかの例外では(可能な場合は)非常に特別な車を正しく処理する必要があります。

したがって、例外のみをキャッチする必要があります。

  • それに対処する方法を正確に知っているもの(例:FileNotFoundExceptionなど)
  • 後でそれらを再レイズするとき(たとえば、失敗後のクリーンアップを実行するため)
  • 例外を別のスレッドに転送する必要がある場合
5
Lucero

それはあなたが必要とするものに依存します。異なるタイプの例外を異なる方法で処理する必要がある場合は、複数のcatchブロックを使用して、できるだけ多くの特定の例外をキャッチする必要があります。

ただし、すべての例外を同じ方法で処理する必要がある場合があります。そのような場合、catch(Exception)は大丈夫かもしれません。例えば:

    try
    {
        DoSomething();
    }
    catch (Exception e)
    {
        LogError(e);
        ShowErrorMessage(e); // Show "unexpected error ocurred" error message for user.
    }
4
Andrew Bezzub

catch(Exception)の2つの許容される使用法を見つけます。

  • アプリケーションの最上位(ユーザーに戻る直前)。これにより、適切なメッセージを提供できます。
  • 低レベルの例外をビジネスの例外としてマスクするために使用します。

最初のケースは自明ですが、2番目のケースを作成します。

実行:

try {
    // xxxx
} catch(Exception e) {
    logger.error("Error XXX",e)
}

@dimitarvpが言ったようにバグマスキングです。

ただし、以下は異なります。

try {
    // xxxx
} catch(Exception e) {
    throw new BussinessException("Error doing operation XXX",e)
}

このようにして、バグを無視してカーペットの下に隠すことはありません。上位のアプリケーション層に、より説明的なメッセージを伴う高レベルの例外を提供しています。

また、適切なレイヤーで例外を管理することも常に重要です。低レベルの例外を上位のビジネスレイヤーにエスカレートする場合、上位のレイヤーが適切に管理することは事実上不可能です。

その場合、私は低レベルの例外を、より適切なコンテキストとメッセージを提供し、詳細に入ることができる元の例外もあるビジネスの例外でマスクすることを好みます。

それでも、より具体的な例外をキャッチしてより適切な処理を提供できる場合は、それを行う必要があります。

コードのブロックでSQLExceptionNetworkExceptionを取得できる場合は、それらをキャッチして、それぞれに適切なメッセージと処理を提供する必要があります。しかし、try/catchブロックの最後でExceptionBussinessExceptionにマッピングしている場合は、問題ありません。実際、上位のサービスレイヤーがビジネス例外(詳細を含む)のみをスローする場合は、これで十分です。

3
lujop

@antharesがまだ回答しているものに加えて:

例外をキャッチすると適切に処理するはずですだからです。また、コード内であらゆる種類の例外を処理することは期待できません。また、すべての例外をキャッチすると、処理できない例外が発生し、スタックの上位にあるコードが適切に処理できないようになる可能性があります。

一般的な原則は、できるだけ具体的なタイプをキャッチすることです。

catch(Exception)は、すべてのRuntimeException(チェックされていない例外)もキャッチするため、不適切な方法です。

1
taringamberini

しかし、時にはそれは大丈夫です!たとえば、あなたが本当に気にしない何か「余分な」ことをするコードがあり、それがあなたのアプリケーションを爆破することを望まないかのように。たとえば、最近、ビジネスパートナーが特定の毎日のトランザクションを新しいログファイルに要約することを望んでいる大きなアプリケーションに取り組みました。彼らは、ログは彼らにとってそれほど重要ではなかった、そしてそれは要件として適格ではなかったと説明しました。これは、処理されているデータを理解するのに役立つ特別なものでした。彼らは他の場所で情報を得ることができたので、彼らはそれを必要としませんでした。そのため、例外をキャッチして飲み込むことが完全に問題ないまれなケースです。

また、すべてのThrowableがキャッチされた会社で働いてから、カスタムのRuntimeExceptionの内部で再スローされました。私はこのアプローチをお勧めしませんが、それが行われたことを指摘するだけです。

0
MattC

これはJava固有の場合があります:

場合によっては、チェックされた例外をスローするメソッドを呼び出す必要があります。これがEJB /ビジネスロジックレイヤーにある場合、2つの選択肢があります。それらをキャッチするか、再スローします。

特定の例外クラスをキャッチするということは、このコードが例外をどのように処理するかを見ると、例外がスローされる可能性があるアクションを再分析する必要があることを意味します。多くの場合、「もしも…」の状況に陥り、例外が正しく処理されている場合は、多くの労力を費やすだけで解決できます。

再スローとは、EJBを呼び出すコードが、通常は呼び出し側クラスに何も意味しないキャッチングコードで散らかされることを意味します。 n.b. EJBメソッドからチェック済み例外をスローすると、トランザクションを手動でロールバックする必要があります。

0

スレッドがその中の例外をキャッチして生き続けることを保証する別の有効なシナリオではないですか?

Thread shouldRunWhenApplicationRuns = new Thread() {
    @Override
    public void run() {
        try {
            // do something that should never end
        } catch (Exception ex) {
            // log it
        }
    };
    shouldRunWhenApplicationRuns.start();
0
opfau