web-dev-qa-db-ja.com

空のcatchブロック

例外がスローされた場合に例外をキャッチする必要がありますが、例外を使用しないでください。つまり、例外が発生する可能性がありますが、発生するかどうかは関係ありません。

私は最近、同様のことについてこの記事を読みました: http://c2.com/cgi/wiki?EmptyCatchClause

この人は、コメントの方法について話します

// should never occur 

コードのにおいであり、コードに表示されることはありません。彼らはその後、コメントがどのように説明します

// don't care if it happens

まったく違うので、自分でこのような状況に遭遇します。たとえば、メールを送信するとき、次のようなことをします。

var addressCollection = new MailAddressCollection();
foreach (string address in addresses)
{
    try
    {
        addressCollection.Add(address);
    }
    catch (Exception)
    {
        // Do nothing - if an invalid email occurs continue and try to add the rest
    }
}

ここで、ユーザーに戻り、1つ以上のメッセージを受信者に送信できないことを説明したいので、これを行うのは悪い考えだと思うかもしれません。しかし、それが単なるCCアドレスである場合はどうでしょうか?それはそれほど重要ではなく、それらのアドレスの1つが無効であったとしても(おそらく単なる誤植でも)メッセージを送信したい場合があります。

したがって、空のcatchブロックを使用するのは正しいのでしょうか、それとも私が知らないより良い代替手段がありますか?

33
Serberuss

特定のタイプの例外が発生したときに本当に何もしたくない場合は、空のcatchブロックを使用することは完全に正しいです。発生するexpectであり、無視しても安全であることがわかっている例外のタイプのみをキャッチすることで、例を改善できます。 Exceptionをキャッチすることで、バグを隠し、プログラムをデバッグしにくくすることができます。

例外処理に関して心に留めておくべきこと:プログラムの外部のエラー状態を通知するために使用される例外、つまりexpectedは少なくとも時々発生する例外と、プログラミングエラー。 1番目の例は、接続がタイムアウトしたために電子メールを配信できなかったこと、またはディスク容量がなかったためにファイルを保存できなかったことを示す例外です。 2番目の例は、メソッドに間違ったタイプの引数を渡そうとしたか、境界外の配列要素にアクセスしようとしたことを示す例外です。

2番目(プログラミングエラー)の場​​合、例外を単に「飲み込む」ことは大きな間違いです。最善の方法は通常、スタックトレースをログに記録し、ユーザーに内部エラーが発生したこと、およびログを開発者(つまりあなた)に送り返すことを伝えるエラーメッセージをポップアップ表示することです。または、開発中に、コンソールにスタックトレースを出力してプログラムをクラッシュさせることもできます。

1つ目(外部の問題)については、「正しい」ことを行うことに関するルールはありません。それはすべて、アプリケーションの詳細に依存します。特定の条件を無視して続行する場合は、そうします。

一般:

技術的な本や記事を読んでいるのは良いことです。そうすることから多くを学ぶことができます。しかし、あなたが読んでいるように、あなたはそのようなことをすることはalways間違っているかalways右。多くの場合、これらの意見は宗教に隣接しています。 [〜#〜] never [〜#〜]特定の方法で物事を行うことは、本や記事(または答えSO ... <咳>)でそう言った。すべてのルールには例外があり、それらの記事を書いている人はアプリケーションの詳細を知りません。あなたがやる。あなたが読んでいるものが理にかなっていることを確認し、もしそうでなければ、あなた自身を信頼してください。

72
Alex D

空のcatchブロックは適切な場所で問題ありません-あなたのサンプルからはcetagorically [〜#〜] not [ 〜#〜]catch (Exception)を使用している。代わりに、発生が予想される明示的な例外をキャッチする必要があります。

その理由は、すべてを飲み込むと、予期していなかった重大な欠陥も飲み込むからです。 「このメールアドレスに送信できません」と「コンピューターのディスク容量が足りません」には、違いがあります。ディスク容量が不足している場合、次の10000通のメールを送信しようとするのは嫌です!

「起こるべきではない」と「起きても構わない」の違いは、「起こるべきではない」場合、does起こります、あなたは静かにそれを飲み込みたくありません!予期しない状況が発生した場合、通常はアプリケーションをクラッシュさせる(または、少なくともクリーンに終了し、何が起こったのかを大量に記録する)ことで、この不可能な状況を特定できます。

18
Dan Puzey

例外が決してスローされるべきではない場合、それをキャッチするポイントはありません-それは決して起こるべきではなく、あなたがそれについて知る必要がある場合。

失敗を引き起こす可能性のある特定のシナリオがある場合は、それらの特定のシナリオをキャッチしてテストし、他のすべてのケースで再スローする必要があります。たとえば、

foreach (string address in addresses)
{
    try
    {
        addressCollection.Add(address);
    }
    catch (EmailNotSentException ex)
    {
        if (IsCausedByMissingCcAddress(ex))
        {
            // Handle this case here e.g. display a warning or just nothing
        }
        else
        {
            throw;
        }
    }
}

上記のコードは、Exceptionをキャッチするのではなく、特定の(架空の場合)例外をキャッチすることに注意してください。スローされると予想される特定の例外タイプをキャッチするのではなく、Exceptionをキャッチすることが正当であるケースはほとんど考えられません。

7
Justin

他の回答の多くは、例外をキャッチしても問題ない場合に十分な理由を示していますが、多くのクラスは、例外をまったくスローしない方法をサポートしています。

多くの場合、これらのメソッドの前には接頭辞Tryが付きます。関数は、例外をスローする代わりに、タスクが成功したかどうかを示すブール値を返します。

この良い例は Parse vs TryParse です

string s = "Potato";
int i;
if(int.TryParse(s, out i))
{
    //This code is only executed if "s" was parsed succesfully.
    aCollectionOfInts.Add(i);
}

ループ内で上記の関数を試して、Parse + Catchと同等の関数と比較すると、TryParseメソッドははるかに高速になります。

5

空のcatchブロックを使用すると、例外を飲み込みます。Exceptionが発生したことを報告している場合でも、常に例外を処理します。

また、汎用Exceptionをキャッチすることは、アプリケーションのバグを隠すことができるため、悪い習慣です。たとえば、ArgumentOutOfRange例外が発生したことに気付いていないのに、それを飲み込んだ(つまり、何もしなかった)場合があります。

2
Darren