try / catch / throwとtry / catch(e)/ throw eの違い


103

違いは何ですか

try { }
catch
{ throw; }

そして

try { }
catch(Exception e)
{ throw e;}

また、どちらを使用すればよいですか?

回答:


151

構造

try { ... }
catch () { ... } /* You can even omit the () here */

try { ... }
catch (Exception e) { ... }

両方がブロック内でスローされたすべての例外をキャッチするという点で似ていtryます(そして、単にこれを使用して例外をログに記録しているのでない限り、避けてください)。これらを見てください:

try { ... }
catch ()
{
    /* ... */
    throw;
}

try { ... }
catch (Exception e)
{
    /* ... */
    throw;
}

try { ... }
catch (Exception e)
{
    /* ... */
    throw e;
}

最初と2番目のtry-catchブロックはまったく同じもので、現在の例外を再スローするだけで、その例外は「ソース」とスタックトレースを保持します。

3番目のtry-catchブロックは異なります。例外をスローすると、ソースとスタックトレースが変更されるため、このメソッドから、throw eそのtry-catchブロックを含むメソッドのその行から例外がスローされたように見えます。

あなたはどちらを使うべきですか?それは本当にそれぞれの場合に依存します。

それをデータベースに永続化Personする.Save()メソッドを持つクラスがあるとしましょう。アプリケーションがPerson.Save()メソッドをどこかで実行するとします。DBがPersonの保存を拒否した場合.Save()、例外がスローされます。throwまたはthrow eこの場合に使用する必要がありますか?まあ、それは異なります。

私が好んでいることは:

try {
    /* ... */
    person.Save();
}
catch(DBException e) {
    throw new InvalidPersonException(
       "The person has an invalid state and could not be saved!",
       e);
}

これにより、DBExceptionが、スローされる新しい例外の「内部例外」として配置されます。したがって、このInvalidPersonExceptionを検査すると、スタックトレースにはSaveメソッドに戻る情報が含まれます(問題を解決するにはこれで十分かもしれません)が、必要な場合は元の例外にアクセスできます。

最後の注意として、例外が予想される場合は、一般的な例外ではなく、その特定の例外を1つキャッチする必要がありますException。つまり、InvalidPersonExceptionが予想される場合は、次のようにします。

try { ... }
catch (InvalidPersonException e) { ... }

try { ... }
catch (Exception e) { ... }

幸運を!


34

1つ目はスタックトレースを保持し、2つ目はリセットします。つまり、2番目のアプローチを使用する場合、例外のスタックトレースは常にこのメソッドから始まり、元の例外トレースを失うことになります。これは、例外の元の原因を見つけることができないため、例外ログを読む人にとっては悲惨です。 。

2番目の方法は、スタックトレースに追加情報を追加する場合に便利ですが、次のように使用されます。

try
{
    // do something
}
catch (Exception ex)
{
    throw new Exception("Additional information...", ex);
}

違いについて議論しているブログ投稿があります。


まあそれは知っておくべき素晴らしいことです!
Myles、

では、なぜ2番目を使用するのですか?最初のものだけを使用する方が良いですか?
Karim、

1
2番目は、特定の例外を確認する必要がある場合、またはOutOfRangeExceptionが頭に浮かぶ場合、またはメッセージをログに記録する必要がある場合などに便利です。1番目は、try {} catch(...){}に類似したワイルドカード例外ハンドラのようですC ++で。
3Dave 2009年

1
David、それはキャッチ(例外e)部分にのみ適用されます。そして、それはthrowvs とは別のものthrow eです。
ヘンクホルターマン

6

あなたは使うべきです

try { }
catch(Exception e)
{ throw }

再スローする前に例外を除いて何かをしたい場合(たとえば、ログ)。孤独な投げはスタックトレースを保持します。


ここで「スロー」を「スローe」に置き換えたらどうなりますか?
Karim、

5

パラメータなしのキャッチとaの違いはcatch(Exception e)、例外への参照を取得することです。フレームワークバージョン2以降、アンマネージ例外はマネージ例外にラップされるため、パラメーターなしの例外は何の役にも立ちません。

違いthrow;とは、throw e;最初のものは、例外を再スローするために使用される2つ目は、新しく作成された例外をスローするために使用されていることです。2番目の例外を使用して例外を再スローすると、新しい例外のように扱われ、最初にスローされた場所からのすべてのスタック情報が置き換えられます。

したがって、あなたは質問のどちらの選択肢も使用しないことをお勧めします。パラメータなしのキャッチを使用throw;しないでください。また、例外を再スローするために使用する必要があります。

また、ほとんどの場合、すべての例外について、基本クラスよりも具体的な例外クラスを使用する必要があります。予期した例外のみをキャッチする必要があります。

try {
   ...
} catch (IOException e) {
   ...
   throw;
}

例外を再スローするときに情報を追加する場合は、元の例外を内部例外として新しい例外を作成し、すべての情報を保持します。

try {
   ...
} catch (IOException e) {
   ...
   throw new ApplicationException("Some informative error message", e);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.