空のキャッチブロックが悪い考えであるのはなぜですか?[閉まっている]


192

私はtry-catchに関する質問を見たことがあります。(Jon Skeetを含め)空のcatchブロックは本当に悪い考えだと言っていますか?なんでこれ?空のキャッチが間違った設計決定ではない状況はありませんか?

たとえば、どこかから追加の情報(Webサービス、データベース)を取得したい場合があり、この情報を取得してもしなくてもかまいません。だからあなたはそれを取得しようとし、何かが起こっても大丈夫です、私は単に「キャッチ(例外は無視されました){}」を追加し、それですべてです


53
空にする必要がある理由を説明するコメントを書きます。
Mehrdad Afshari、

5
...または少なくともそれが捕捉されたことをログに記録します。
マットb

2
@ocdecio:クリーンアップコードの場合は避けてください。一般的には避けないでください。
John Saunders、

1
@ocdecio:try..catchの使用を回避するもう1つのケースは、既知のタイプの障害の例外をキャッチする場合です。例:数値変換の例外
MPritchard

1
@ocdecio-try..finallyはtry..empty catchよりも優れています。エラーがスタックを継続するためです。フレームワークによって処理されるか、プログラムを強制終了してユーザーに表示されるためです。両方の結果が "サイレント障害」。
ネイト

回答:


297

エラー状態を黙って飲み込んでから実行を続けるため、通常は空のtry-catchはお勧めできません。時々、これは正しいことかもしれませんが、多くの場合、開発者が例外を見つけ、それについて何をすべきかわからず、空のキャッチを使用して問題を沈黙させたことを示しています。

これは、エンジン警告灯の上に黒いテープを置くのと同等のプログラミングです。

例外をどのように処理するかは、ソフトウェアのどのレイヤーで作業しているのかによって異なると思います:Exceptions in the Rainforest


4
私はそれらの本当にまれな状況で、本当に例外必要はありませんし、ログが何らかの理由で利用できない、私はそれが意図的だとのコメントを確認してください-と、なぜそれが必要ではない、と私はまだどうかをログに記録することを好むだろうと改めて表明それはその環境で実現可能でした。基本的に、私がコメントをするのは、それがその状況でのオプションであったならば、ロギングよりも多くの作業をすることです。幸いなことに、私は2人のクライアントを抱えていますが、これが問題となっています。それは、Webサイトから重要ではない電子メールを送信するときだけです。
ジョンルディ

37
また、類推も大好きです。すべてのルールと同様に、例外もあります。たとえば、(VCRが何であるかを覚えているすべての古い人々のために)時限録音を行うつもりがない場合は、VCRの点滅している時計に黒いテープを使用してもまったく問題ありません。
マイケル・バー

3
認められた実践からの脱却と同様に、適切な場合はそれを行い、それを文書化して、次の担当者があなたが何をしたのか、そしてその理由を知ってください。
David Thornley、

5
@ジェイソン:少なくとも、例外を沈黙させている理由を説明する詳細なコメントを含める必要があります。
Ned Batchelder 2010

1
この回答は2つのことを前提としています。1.スローされている例外は確かに意味のあるものであり、スローするコードを書いた人は彼が何をしていたかを知っていました。2.例外が実際に「エラー状態」であり、制御フローとして悪用されないこと(これは私の最初のポイントのより具体的なケースです)。
Boris B.

37

これは、障害(より一般的には例外的な状態)が適切に満たされ、応答がまったくない本当にまれな状態であるため、一般的には悪い考えです。その上、空のcatchブロックは、例外エンジンを使用して、プリエンプティブに実行する必要があることをエラーチェックする人々が使用する一般的なツールです。

それが常に悪いと言うのは本当ではない...それはほとんど本当ではない。エラーが発生したことを気にしないか、エラーの存在がどういうわけかそれについて何もできないことを示している場合があります(たとえば、以前のエラーをテキストログファイルに書き込んだり、と表示されますIOException。つまり、新しいエラーを書き出すことができませんでした)。


11

空のcatchブロックを使用するのは悪いプログラマーであり、彼が何をしているのかわからない、とまでは言いません。

必要に応じて、空のcatchブロックを使用します。時々、私が消費しているライブラリのプログラマーは、彼が何をしているかわからず、だれもそれを必要としない状況でも例外をスローします。

たとえば、いくつかのhttpサーバーライブラリについて考えてみましょindex.htmlう。クライアントが切断されて送信できなかったためにサーバーが例外をスローしたとしても、それほど気にすることはできませんでした。


6
あなたは確かに過度に一般化しています。理由だけであなたはそれが誰もいないことを意味するものではありません必要はありません。応答で絶対に何もできない場合でも、破棄された接続の統計を収集する必要がある誰かがどこかにいます。したがって、「ライブラリのプログラマは彼が何をしているか知らない」と仮定するのは非常に失礼です。
Ben Voigt 2013

8

正当化できるまれな例があります。Pythonでは、次のような構成がよく見られます。

try:
    result = foo()
except ValueError:
    result = None

したがって、(アプリケーションによっては)実行しても問題ない場合があります。

result = bar()
if result == None:
    try:
        result = foo()
    except ValueError:
        pass # Python pass is equivalent to { } in curly-brace languages
 # Now result == None if bar() returned None *and* foo() failed

最近の.NETプロジェクトでは、特定のインターフェイスを実装するクラスを見つけるためにプラグインDLLを列挙するコードを記述する必要がありました。関連するコード(VB.NETでは申し訳ありません)は次のとおりです。

    For Each dllFile As String In dllFiles
        Try
            ' Try to load the DLL as a .NET Assembly
            Dim dll As Assembly = Assembly.LoadFile(dllFile)
            ' Loop through the classes in the DLL
            For Each cls As Type In dll.GetExportedTypes()
                ' Does this class implement the interface?
                If interfaceType.IsAssignableFrom(cls) Then

                    ' ... more code here ...

                End If
            Next
        Catch ex As Exception
            ' Unable to load the Assembly or enumerate types -- just ignore
        End Try
    Next

この場合でも、どこかに障害を記録することはおそらく改善になると認めます。


私はあなたの答えを見る前に、log4netをそれらのインスタンスの1つと呼びました。
スコットローレンス、

7

空のcatchブロックは通常、コーダーが実際に何をしているのかわからないために挿入されます。私の組織では、空のcatchブロックに、例外を除いて何もしないことが良い考えである理由に関するコメントを含める必要があります。

関連する注意として、ほとんどの人はtry {}ブロックの後にcatch {}またはfinally {}を続けることができることを知りませんが、必要なのは1つだけです。


1
+1追加の影響について、最後の文の「または」を強調します
MPritchard

しかし、その2番目の段落は言語に依存する可能性がありますよね?
David Z、

3
当然のない限り、あなたはキャッチがIE6またはIE7 ;-) ...の話をしているIS必要か最終的には実行されません。(これはIE8で修正されました)
scunliffe 2009


とても本当です。言語を強調する価値があるかもしれません。.netは問題ないと思います
MPritchard 09

7

例外は、本当に例外がある場合にのみスローする必要があります-何かが標準を超えて起こっています。空のcatchブロックは基本的に「何か悪いことが起こっていますが、私は気にしません」と言っています。これは悪い考えです。

例外を処理したくない場合は、例外を処理できるコードに到達するまで、例外を上方に伝播させます。例外を処理できるものがなければ、アプリケーションを停止する必要があります。


3
時には、それが何にも影響を及ぼさないことを知っています。次に、それを実行し、コメントしてください。そうすれば、次の男は無能だからといって、あなたが台無しにされたとは思わないでしょう。
David Thornley、

ええ、すべてのための時間と場所があります。ただし、一般的には、空のcatchブロックが良いことはルールの例外だと思います。例外を本当に無視したい場合はまれです(通常、IMO、例外の不適切な使用の結果です)。
リードコプシー

2
@David Thornley:少なくとも例外を調べて、それが予期された意味のないエラーであるのか、それとも上に伝播する必要のあるエラーであるのかを判断しなければ、それが何にも影響を与えないことをどうやって知るのですか?
Dave Sherohman、2009

2
@デイブ:catch (Exception) {}悪い考えですcatch (SpecificExceptionType) {}が、完全に良いかもしれません。プログラマーは、catch節の型情報を使用して、例外を検査します。
Ben Voigt 2013

7

私はあなたがキャッチした場合、それは大丈夫だと思う特定の例外タイプをそのあなたは一つだけのために提起することになるだろう知っている特定理由でその例外を予期していて、何もする必要がない場合は問題ないと思います。

ただし、その場合でも、デバッグメッセージが適切な場合があります。


5

パージョシュブロッホ - 項目65:Doが例外無視しない効果的なJavaの

  1. 空のcatchブロックは、例外の目的を無効にします
  2. 少なくとも、catchブロックには、例外を無視することが適切である理由を説明するコメントを含める必要があります。

3

空のcatchブロックは、本質的に「どのエラーがスローされたのか知りたくないので、無視するだけです」と言っています。

これはVB6と似てOn Error Resume Nextいますが、例外がスローされた後のtryブロックのすべてがスキップされる点が異なります。

これは、何かが壊れたときに役に立ちません。


実際には「On Error Resume Next」の方が悪いと思います-関係なく次の行を試すだけです。空のキャッチは、tryステートメントの
右中

いい視点ね。私はおそらく私の応答でそれを注意する必要があります。
パワーロード2009

1
これは厳密には当てはまりません。特定の例外タイプの空のtry ... catchがある場合、このタイプの例外だけが無視され、それは正当なものになる可能性があります...
Meta-Knight

ただし、特定のタイプの例外がスローされていることがわかっている場合は、try-catchを使用して状況に対処しない方法でロジックを作成するのに十分な情報がある可能性があります。
スコットローレンス、

@Scott:特定の言語(Javaなど)が例外をチェックしています...キャッチブロックを作成する必要がある例外。
パワーロード2009

3

これは、「プログラムフローを制御するために例外を使用しないでください。」および「例外的な状況でのみ例外を使用する」と密接に関連しています。これらが実行された場合、問題が発生した場合にのみ例外が発生します。そして問題があれば、黙って失敗したくないでしょう。問題を処理する必要がないまれな異常では、異常が異常でなくなった場合に備えて、少なくとも例外をログに記録する必要があります。失敗するより悪い唯一のことは、静かに失敗することです。


2

例外を無視することがコードの意図された動作であったと推測する方法がないため、完全に空のcatchブロックは悪い考えだと思います。例外を飲み込み、場合によってはfalseまたはnullまたはその他の値を返すことは必ずしも悪いことではありません。.netフレームワークには、このように動作する多くの「try」メソッドがあります。経験則として、例外を飲み込んだ場合、アプリケーションがロギングをサポートしている場合は、コメントとログステートメントを追加します。


1

例外スローされた場合、それが表示されることはないため、サイレントで失敗することが最悪の選択肢です。誤った動作が発生し、どこで発生しているかがわからなくなります。少なくともそこにログメッセージを入れてください!それは「決して起こりえないこと」だとしても!


1

空のcatchブロックは、プログラマが例外をどうするかわからないことを示しています。それらは、例外が発生し、別のtryブロックによって正しく処理されることから、例外を抑制しています。あなたがキャッチしていることを除いて、常に何かを試してみてください。


1

空のcatchステートメントで最も煩わしいのは、他のプログラマがそれを行ったときです。つまり、誰か他の人からコードをデバッグする必要がある場合、空のcatchステートメントによって、そのような作業がより困難になります。IMHO catchステートメントは常に何らかのエラーメッセージを表示する必要があります-エラーが処理されない場合でも、少なくともそれを検出する必要があります(デバッグモードでのみオン)


1

考えられるすべての例外を黙って渡しいるため、これはおそらく正しいことではありません。予期している特定の例外がある場合は、それをテストし、例外でない場合は再スローする必要があります。

try
{
    // Do some processing.
}
catch (FileNotFound fnf)
{
    HandleFileNotFound(fnf);
}
catch (Exception e)
{
    if (!IsGenericButExpected(e))
        throw;
}

public bool IsGenericButExpected(Exception exception)
{
    var expected = false;
    if (exception.Message == "some expected message")
    {
        // Handle gracefully ... ie. log or something.
        expected = true;
    }

    return expected;
}

1
これは、実際に使用するようにアドバイスしている標準的なパターンではありません。ほとんどの人は、期待しているタイプの例外をキャッチするだけで、そうでないものはキャッチしません。私はあなたのアプローチが有効であるいくつかの状況を見ることができます、最初に理解していないので人々がこのようなものを読む傾向があるこのようなフォーラムに投稿するのに注意してください;)
MPritchard

私の意図は、IsKnownException()が例外のタイプをチェックする(そう、別のcatchブロックで行う必要がある)ことではなく、予期される例外であるかどうかをチェックすることです。わかりやすくするために編集します。
xanadont 2009

私はもともとCOMExceptionsについて考えていました。特定のErrorCodeをテストして、期待するコードを処理できます。これは、ArcOjbectsでプログラミングするときによく行います。
xanadont 2009

2
-1例外メッセージに基づいてコードで決定を下すことは非常に悪い考えです。正確なメッセージが文書化されることはほとんどなく、いつでも変更される可能性があります。実装の詳細です。または、メッセージはローカライズ可能なリソース文字列に基づいている場合もあります。いずれにせよ、それは人間によって読まれるだけのものです。
Wim Coenen、

ねえ。exception.Messageはローカライズされている可能性があるため、期待どおりではありません。これは間違っています。
フランクホーマー

1

一般に、実際に処理できる例外のみをキャッチする必要があります。つまり、例外をキャッチするときはできるだけ具体的にします。すべての例外をキャッチすることはめったになく、すべての例外を無視することはほとんど常に非常に悪い考えです。

空のcatchブロックがいくつかの意味のある目的を持っているいくつかの例だけを考えることができます。特定の例外が発生しても、アクションを再試行するだけでキャッチされている場合は、「キャッチ」ブロックで何もする必要はありません。ただし、例外が発生したという事実をログに記録することをお勧めします。

別の例:CLR 2.0は、ファイナライザスレッドの未処理の例外の処理方法を変更しました。2.0より前のバージョンでは、プロセスはこのシナリオに耐えることができました。現在のCLRでは、ファイナライザスレッドで未処理の例外が発生した場合、プロセスが終了します。

ファイナライザが本当に必要な場合にのみファイナライザを実装し、それでもファイナライザで可能な限り少しを行う必要があることに注意してください。ただし、ファイナライザが実行する必要がある作業が例外をスローする可能性がある場合は、2つの悪の小さい方を選択する必要があります。未処理の例外が原因でアプリケーションをシャットダウンしますか?または、多かれ少なかれ未定義の状態で続行しますか?少なくとも理論的には、後者はいくつかのケースでは2つの悪のうち小さい方かもしれません。これらの場合、空のcatchブロックはプロセスの終了を妨げます。


1
たとえば、どこかから追加の情報(Webサービス、データベース)を取得したい場合があり、この情報を取得してもしなくてもかまいません。だからあなたはそれを取得しようとし、何かが起こっても大丈夫です、私は単に「キャッチ(例外は無視されました){}」を追加し、それですべてです

したがって、あなたの例を考えると、すべての例外をキャッチして無視しているので、その場合はお勧めできません。捕まえEInfoFromIrrelevantSourceNotAvailableてそれを無視していたとしても、それは問題ありませんが、そうではありません。またENetworkIsDown、を無視しているため、重要な場合とそうでない場合があります。あなたは無視しているENetworkCardHasMeltedEFPUHasDecidedThatOnePlusOneIsSeventeen、これらはほぼ間違いなく重要です。

重要でないとわかっている特定のタイプの例外のみをキャッチ(および無視)するように設定されている場合、空のcatchブロックは問題になりません。すべての例外を抑制し、黙って無視することをお勧めします。最初に例外を調べて、それらが予期されている/正常/無関係であるかどうかを確認するのを止めることはありませんが、非常にまれです。


1

あなたがそれらを使用するかもしれない状況がありますが、それらは非常にまれであるべきです。私が使用する可能性のある状況は次のとおりです。

  • 例外ロギング。コンテキストによっては、未処理の例外またはメッセージをポストする必要がある場合があります。

  • レンダリング、サウンド処理、リストボックスコールバックなどの技術的な状況のループ。動作自体が問題を実証し、例外をスローすると邪魔になり、例外をログに記録すると、おそらく「数百のXXXに失敗」というメッセージが表示されます。 。

  • 少なくとも何かをログに記録しているはずですが、失敗することのないプログラム。

ほとんどのwinformsアプリケーションでは、すべてのユーザー入力に対して1つのtryステートメントがあれば十分であることがわかりました。私は次の方法を使用します:(AlertBoxは単なるMessageBox.Showラッパーです)

  public static bool TryAction(Action pAction)
  {
     try { pAction(); return true; }
     catch (Exception exception)
     {
        LogException(exception);
        return false;
     }
  }

  public static bool TryActionQuietly(Action pAction)
  {
     try { pAction(); return true; }
     catch(Exception exception)
     {
        LogExceptionQuietly(exception);
        return false;
     }
  }

  public static void LogException(Exception pException)
  {
     try
     {
        AlertBox(pException, true);
        LogExceptionQuietly(pException);
     }
     catch { }
  }

  public static void LogExceptionQuietly(Exception pException)
  {
     try { Debug.WriteLine("Exception: {0}", pException.Message); } catch { }
  }

次に、すべてのイベントハンドラーは次のような処理を実行できます。

  private void mCloseToolStripMenuItem_Click(object pSender, EventArgs pEventArgs)
  {
     EditorDefines.TryAction(Dispose);
  }

または

  private void MainForm_Paint(object pSender, PaintEventArgs pEventArgs)
  {
     EditorDefines.TryActionQuietly(() => Render(pEventArgs));
  }

理論的には、TryActionSilentlyを使用できます。これは、例外が無限のメッセージを生成しないように、呼び出しのレンダリングに適している場合があります。


1

catchブロックで何をすべきかわからない場合は、この例外をログに記録できますが、空白のままにしないでください。

        try
        {
            string a = "125";
            int b = int.Parse(a);
        }
        catch (Exception ex)
        {
            Log.LogError(ex);
        }

なぜこれは反対票が投じられたのですか?
Vino

0

空のcatchブロックを使用することはできません。それはあなたが知っている間違いを隠すようなものです。少なくとも、時間がない場合は、後で確認するためにログファイルに例外を書き出す必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.