2009-11-08 13 views

答えて

127

構造

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; 
} 

第一及び第二のtry-catchブロックがまったく同じことです、彼らは単に現在の例外を再スローし、その例外は、その「ソース」とスタックトレースを維持します。

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

どちらを使用しますか?それは本当にそれぞれの場合に依存します。

.Save()メソッドを持つPersonクラスを持ち、それをデータベースに保持するとします。アプリケーションが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メソッドに戻る情報が含まれます(問題を解決するのに十分かもしれませんが)。必要に応じて元の例外にアクセスできます。

あなたが選ぶべきInvalidPersonExceptionを期待している場合は、例外を期待しあり、最終的な発言として、あなたは本当に、すなわち、一般Exceptionその1つの特定の例外をキャッチし、そしてべきではありません。

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

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

幸運!

30

最初のスタックトレースは、2番目のスタックトレースをリセットしている間は保持します。つまり、2番目の方法を使用した場合、例外のスタックトレースは常にこのメソッドから開始され、元の例外トレースを失うことになります。これは、例外ログの読者が例外の元の原因。

第二のアプローチでは、スタックトレースに追加情報を追加したいときに便利かもしれないが、それはこのように使用されます。

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

の違いを議論するブログpostがあります。

+0

まあ知っている素晴らしいものです! – Myles

+0

だから、なぜ2番目の? 最初のものだけを使う方が良いですか? – Karim

+1

特定のexceptinonsをチェックする必要があるときに便利です - OutOfRangeExceptionが気になる - またはメッセージなどを記録する必要があります。最初はtry {} catch(...){と同様のワイルドカード例外ハンドラであるようです} C++で。 –

6

あなたが(たとえばログイン)を再スローする前に例外を除いて何かをしたい場合は、

try { } 
catch(Exception e) 
{ throw } 

を使用する必要があります。孤独なスローはスタックトレースを保持します。

+0

と私はここで "スロー"を "スロー"と置き換えた場合どうなりますか? – Karim

+3

Darinが指摘するように、 "throw e"はスタックトレースをリセットします。 –

4

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

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

だから、質問の中のいずれかの選択肢を使用しないでください。パラメータのないキャッチは使用しないでください。例外を再現するには、throw;を使用する必要があります。

また、ほとんどの場合、すべての例外に対して、より具体的な例外クラスを基底クラスより使用する必要があります。予期した例外を捕捉するだけです。

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

あなたはすべての情報preservereする例外を再スローするとき、あなたは内部例外として、元の例外を持つ新しい例外を作成する任意の情報を追加したい場合は :

try { 
    ... 
} catch (IOException e) { 
    ... 
    throw new ApplicationException("Some informative error message", e); 
} 
関連する問題