try-catchの質問 を見たところ、空のcatchブロックは本当に悪い考えだと人々(Jon Skeetを含む)は言っていますか?なんでこれ?空のキャッチが間違った設計決定ではない状況はありませんか?
たとえば、どこか(Webサービス、データベース)から追加の情報を取得したい場合がありますが、この情報を取得してもしなくてもかまいません。だからあなたはそれを取得しようとします、そして何かが起こっても大丈夫です、私は単に「catch(Exception ignored){}」を追加し、それがすべてです
通常、空のtry-catchは、エラー状態を静かに飲み込んでから実行を継続するため、悪い考えです。時々これは正しいことかもしれませんが、多くの場合、開発者が例外を見つけ、それについて何をすべきかを知らなかったため、空のキャッチを使用して問題を沈黙させた兆候です。
これは、エンジン警告灯に黒いテープを貼ることに相当するプログラミングです。
例外にどのように対処するかは、使用しているソフトウェアのレイヤーによって異なります。 熱帯雨林の例外 。
彼らは悪い考えです一般的にそれは失敗(例外条件、より一般的には)が全く応答なしで適切に満たされる本当にまれな状態だからです。さらに、空のcatch
ブロックは、例外エンジンを使用してプリエンプティブに実行する必要があることをエラーチェックする人々が使用する一般的なツールです。
always badであると言うのは正しくありません...それはごくわずかです。エラーが発生したことを気にしないか、エラーの存在が何らかの形でそれについて何もできないことを示している場合があります(たとえば、以前のエラーをテキストログファイルに書き込み、 IOException
を受け取ります。これは、とにかく新しいエラーを書き出すことができなかったことを意味します)。
空のcatchブロックを使用するのは悪いプログラマであり、彼が何をしているのかわからないと言う限り、私は物事を伸ばすつもりはありません...
必要に応じて、空のcatchブロックを使用します。私が使っているライブラリのプログラマーは、彼が何をしているのか分からず、誰もそれを必要としない状況でも例外を投げることがあります。
たとえば、いくつかのhttpサーバーライブラリを考えてみてください。クライアントが切断してindex.html
を送信できなかったためにサーバーが例外をスローしても、それほど気にすることはできませんでした。
正当化できるまれな例があります。 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
この場合でも、どこかで障害をログに記録することでおそらく改善されることは認めます。
通常、空のcatchブロックは、コーダーが何をしているかを実際に知らないために入れられます。私の組織では、空のcatchブロックに、例外で何もしないことが良いアイデアである理由に関するコメントを含める必要があります。
関連する注意事項として、ほとんどの人はtry {}ブロックの後にcatch {}またはfinally {}が続くことを知らないため、1つだけが必要です。
例外は、本当に例外がある場合にのみスローされるべきです-何かが標準を超えて起こっています。空のcatchブロックは基本的に「何か悪いことが起こっていますが、私は気にしません」と言っています。これは悪い考えです。
例外を処理したくない場合は、例外を処理できるコードに到達するまで上方に伝播させます。何も例外を処理できない場合は、アプリケーションを停止する必要があります。
特定の理由が1つだけ発生することがわかっている特定の例外タイプをキャッチしても大丈夫だと思いますが、その例外を期待し、実際にはそうではありませんそれについて何かする必要があります。
ただし、その場合でも、デバッグメッセージが正常に表示される場合があります。
PerJosh Bloch-Item 65:例外を無視しないでくださいof有効なJava:
これは、「プログラムフローを制御するために例外を使用しないでください」、および「例外的な状況にのみ例外を使用する」と密接に関係しています。これらが行われた場合、例外は問題がある場合にのみ発生するはずです。また、問題がある場合は、黙って失敗したくありません。問題を処理する必要のないまれな異常では、異常が異常でなくなった場合に備えて、少なくとも例外をログに記録する必要があります。失敗よりも悪いことは、黙って失敗することだけです。
空のcatchブロックは、基本的に「どのエラーがスローされたかを知りたくないので、無視するだけです」と言っています。
VB6のOn Error Resume Next
と似ていますが、例外がスローされた後のtryブロック内のすべてのものがスキップされる点が異なります。
何かが壊れたときに助けにはなりません。
完全に空のcatchブロックは、例外を無視することがコードの意図した動作であると推測する方法がないため、悪い考えだと思います。例外を飲み込み、場合によってはfalseまたはnullまたはその他の値を返すことは必ずしも悪いことではありません。 .netフレームワークには、このように動作する多くの「try」メソッドがあります。例外を飲み込む場合の経験則として、アプリケーションがロギングをサポートしている場合はコメントとログステートメントを追加します。
空のcatchステートメントで最も迷惑なのは、他のプログラマーがそれをしたときです。つまり、他の誰かからコードをデバッグする必要がある場合、空のcatchステートメントがあると、そのような作業が必要以上に難しくなります。 IMHO catchステートメントは常に何らかのエラーメッセージを表示する必要があります-エラーが処理されない場合でも、少なくともそれを検出する必要があります(alt。onデバッグモードのみ)
通常、実際に処理できる例外のみをキャッチする必要があります。これは、例外をキャッチするときにできる限り具体的にすることを意味します。すべての例外をキャッチすることはめったに良いアイデアではありませんし、すべての例外を無視することはほとんど常に非常に悪いアイデアです。
空のcatchブロックに意味のある目的があるいくつかの例しか考えられません。特定の例外がキャッチされる場合、アクションを再試行するだけで「処理」される場合、キャッチブロックで何もする必要はありません。ただし、例外が発生したという事実をログに記録することをお勧めします。
別の例:CLR 2.0は、ファイナライザースレッドの未処理の例外の処理方法を変更しました。 2.0より前のプロセスは、このシナリオに耐えることができました。現在のCLRでは、ファイナライザースレッドで未処理の例外が発生した場合、プロセスは終了します。
ファイナライザは、本当に必要な場合にのみ実装し、その場合でもファイナライザで少しだけ実行する必要があることに注意してください。しかし、ファイナライザが実行しなければならない処理が例外をスローする可能性がある場合は、2つの悪のどちらか小さい方を選択する必要があります。未処理の例外のためにアプリケーションをシャットダウンしますか?または、多かれ少なかれ未定義の状態で続行しますか?少なくとも理論的には、後者は、いくつかのケースでは2つの悪の小さい方かもしれません。これらの場合、空のcatchブロックはプロセスの終了を妨げます。
あなたがそれらを使用するかもしれない状況がありますが、それらは非常にまれであるはずです。使用する可能性のある状況は次のとおりです。
例外ロギング;コンテキストに応じて、未処理の例外またはメッセージを代わりに投稿することができます。
レンダリングやサウンド処理、リストボックスコールバックなど、動作自体が問題を示し、例外をスローすると障害が発生し、例外をログに記録すると「XXXに失敗しました」というメッセージが発生する可能性があります。
cannot失敗するプログラム。ただし、少なくとも何かを記録する必要があります。
ほとんどの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を使用できます。これは、例外が無限の量のメッセージを生成しないように呼び出しをレンダリングするのに適している場合があります。
例外isがスローされた場合、あなたはそれを見ることはないだろう-黙って失敗することが最悪の選択肢である-あなたは間違った振る舞いをして、それがどこで起こっているか見当がつかないだろうから。少なくともそこにログメッセージを入れてください!たとえそれが「決して起こらない」ものであっても!
空のcatchブロックは、プログラマーが例外の処理方法を知らないことを示しています。例外がバブリングし、別のtryブロックによって正しく処理される可能性を抑制しています。キャッチしている例外を除いて、常に何かを試してみてください。
あなたは黙ってevery可能性のある例外を渡しているので、おそらく正しいことではないでしょう。予期している特定の例外がある場合は、それをテストし、例外でない場合は再スローする必要があります。
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;
}
たとえば、どこか(Webサービス、データベース)から追加の情報を取得したい場合がありますが、この情報を取得してもしなくてもかまいません。だからあなたはそれを取得しようとします、そして何かが起こっても大丈夫です、私は単に「catch(Exception ignored){}」を追加し、それがすべてです
したがって、あなたの例で言えば、all例外をキャッチして無視しているので、その場合は悪い考えです。 EInfoFromIrrelevantSourceNotAvailable
のみをキャッチして無視した場合、それは問題ありませんが、そうではありません。また、重要な場合とそうでない場合があるENetworkIsDown
も無視しています。 ENetworkCardHasMelted
とEFPUHasDecidedThatOnePlusOneIsSeventeen
は無視しますが、これらはほぼ確実に重要です。
空のcatchブロックは、重要でないとわかっている特定のタイプの例外のみをキャッチ(および無視)するように設定されている場合は問題になりません。 all例外を抑制し、黙って無視することをお勧めします。まず例外を調べて、それらが予期される/正常/無関係であるかどうかを確認しますが、非常にまれです。
空のcatchブロックを使用しないでください。知っている間違いを隠すようなものです。少なくとも、時間に追われている場合は後で確認するために、ログファイルに例外を書き出す必要があります。