204

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

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

4

20 に答える 20

309

通常、空の try-catch は悪い考えです。エラー状態を静かに飲み込んでから実行を継続するからです。場合によっては、これが正しいこともありますが、多くの場合、開発者が例外を認識し、それに対して何をすべきかわからなかったため、空のキャッチを使用して問題を黙らせたという兆候です。

これは、エンジンの警告灯に黒いテープを貼るのと同じプログラミングです。

例外をどのように処理するかは、作業しているソフトウェアの層によって異なると思います:熱帯雨林の例外

于 2009-08-05T16:34:31.320 に答える
37

失敗 (より一般的には例外的な状態) が適切に満たされ、応答がまったくないという非常にまれな状態であるため、これらは一般的に悪い考えです。その上、空のcatchブロックは、例外エンジンを使用して事前に実行する必要があるエラー チェックに使用する一般的なツールです。

それが常に悪いと言うのは真実ではありません...それはほとんど真実ではありません. エラーがあったことを気にしない場合や、エラーの存在が何らかの形でそれについて何もできないことを示している場合があります (たとえば、以前のエラーをテキスト ログ ファイルに書き込んで、IOExceptionとにかく、新しいエラーを書き出すことができなかったことを意味します) 。

于 2009-08-05T16:35:10.350 に答える
11

空の catch ブロックを使用する人は悪いプログラマーであり、彼が何をしているのかわからないと言う限り、私は物事を引き延ばしません...

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

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

于 2009-08-05T16:58:35.843 に答える
9

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

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

于 2009-08-05T16:35:27.043 に答える
9

特定の理由でのみ発生することがわかっている特定の例外タイプをキャッチしても問題ないと思います。その例外を予期していて、実際には何もする必要はありません。

しかし、その場合でも、デバッグ メッセージが適切である可能性があります。

于 2009-08-05T16:35:55.637 に答える
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

この場合でも、失敗をどこかに記録することでおそらく改善されることは認めます。

于 2009-08-05T17:31:37.023 に答える
7

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

これに関連して、ほとんどの人は、try{} ブロックの後に catch{} または finally{} のいずれかが続く可能性があることを知りません。必要なのは 1 つだけです。

于 2009-08-05T16:34:03.770 に答える
3

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

On Error Resume Next例外がスローされた後の try ブロック内のすべてがスキップされることを除いて、VB6 の に似ています。

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

于 2009-08-05T16:35:17.073 に答える
3

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

于 2009-08-05T23:55:19.947 に答える
2

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

于 2009-08-05T16:37:25.823 に答える
2

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

于 2009-08-05T18:13:26.237 に答える
2

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

        try
        {
            string a = "125";
            int b = int.Parse(a);
        }
        catch (Exception ex)
        {
            Log.LogError(ex);
        }
于 2013-09-12T08:00:17.213 に答える
1

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

于 2009-08-05T16:36:05.497 に答える
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;
}
于 2009-08-05T16:37:40.550 に答える
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を使用できます。これは、例外が無限の量のメッセージを生成しないように、呼び出しをレンダリングするのに適している場合があります。

于 2012-01-19T00:53:54.460 に答える
1

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

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

したがって、あなたの例では、すべての例外をキャッチして無視しているため、その場合は悪い考えです。キャッチEInfoFromIrrelevantSourceNotAvailableして無視するだけなら問題ありませんが、そうではありません。ENetworkIsDownまた、重要である場合とそうでない場合がある を無視しています。あなたは無視していますENetworkCardHasMeltedEFPUHasDecidedThatOnePlusOneIsSeventeen、これはほぼ確実に重要です。

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

于 2009-08-07T12:16:39.783 に答える
1

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

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

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

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

于 2009-08-07T11:37:13.627 に答える
0

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

于 2009-12-11T02:24:25.277 に答える