私は自分のコードの一部をクリーンアップすることに取り組んでいますが、どちらのルートが良いかわからないところに来ました。
現在、メソッドの大部分で1つのtry catchブロックを使用しており、最後にいくつかの個別の例外を処理しますが、メンテナンスのためだけにtry catchブロックを増やす方がよいと考えました。しかし、コードを分解していると、同じタイプの例外に対して複数のブロックを記述しているところになりました。ブロックが失敗した理由をより詳細に説明できるため、各パーツのブロックを作成する利点がわかります。
私の質問はこれです...これを行うには欠点がありますか?パフォーマンスの問題や、表示されていない他の隠されたモンスターがありますか?
また、メソッド内の複数の例外を処理する好ましい方法は何ですか、業界標準はありますか?
私のポイントをより良く説明するために、ここにいくつかの擬似コードがあります
//multiple try catch for same exception
try {
//some code here
} catch (MyException e) {
//specific error message here
}
try {
//some different code here
} catch (MyException e) {
//more specific error message indicating a different issue
}
私は常に、読みやすさと保守性のためにネストのレベルを下げようとします。 n個のtry/catchブロックがあり、それぞれが同じタイプの例外を処理している場合、例外をメソッドにスローできるコードをリファクタリングしないでください...次のようになります。
try {
firstBatchOfTricky();
secondBatchOfTricky();
....
nthBatchOfTricky();
} catch (ItWentBoomException e) {
// recover from boom
} catch (ItWentBangException e) {
// recover from bang
}
これは、複数のtry/catchingを行うよりもはるかに読みやすくなっています。メソッドは、自己文書化コードの精神でメソッドが行うことを記述する必要があることに注意してください。
独自の例外タイプがあるため、必要なデータを例外に追加して、catchブロックでさまざまな処理を実行できます。 「より具体的なメッセージ」と言うときは、詳細なメッセージとともに例外をスローするだけです。複数のcatchブロックは必要ありません。例外の状態に基づいて劇的に異なることをしたい場合は、より多くの例外タイプを作成してブロックをキャッチしますが、私の擬似コードが示すように、1つのtryブロックのみを...
最後に、例外から回復できない場合は、catchブロックでコードを乱雑にしないでください。ランタイム例外をスローして、バブルさせます。 (コメントの@tonyからの良いアドバイス)
これはパフォーマンスや個人的な好みの質問ではありません。機能と要件の質問です。
私が書くと仮定します:
シナリオ1:
try
{
doThingA();
}
catch (SomeException panic)
{
System.out.println("doThingA failed");
}
try
{
doThingB();
}
catch (SomeException panic)
{
System.out.println("doThingB failed");
}
シナリオ2:
try
{
doThingA();
doThingB();
}
catch (SomeException panic)
{
System.out.println("doThingA or doThingB failed");
}
これら2つのシナリオは同等ではありません。異なる動作をします。シナリオ1では、doThingAが例外をスローした場合、doThingBは引き続き実行されます。シナリオ2では、doThingAが例外をスローした場合、doThingBは実行されません。だから、問題はどちらがより良いパフォーマンスを提供するか、より読みやすいコードではなく、doThingAが失敗した場合、doThingBをまだ実行すべきかどうかです?
本当に欲しいのは2番目の動作であるが、ユーザーに何が間違っているかを伝えるために異なるメッセージが必要な場合は、異なる例外をスローするか、メッセージのテキストを例外に入れる必要があります。
void doThingA() throws SomeException
{
... whatever code ...
if (theWorldIsAboutToEnd)
throw new SomeException("doThingA failed");
}
次に、catch句で、定数文字列を表示する代わりに、SomeException.toStringまたはSomeException.getMessageを表示します。
例外を異なる方法で処理できる場合(異なるエラーメッセージなど)、例外を個別にキャッチするのが適切です。
例外のタイプが異なる場合、それは別のtryブロックを持つ必要があるという意味ではなく、複数のcatchを持つ1つのtryブロックを持つことができます。
それは完全にシナリオに依存しています。セキュリティ例外をスローする処理を多数行い、そのシナリオを同じ方法で処理する場合、そのためにtryブロックを使用できます。
ただし、多くの小さなtry/catchブロックを使用する方が私の意見ではより良い場合が多いと言いました。大きなtry/catchを使用することは、gotoがどこから来たかわからないことを除いて、いくつかのgotoステートメントを使用することに似ています。
たとえば、下の例では、どのメソッドがexception1に、どのメソッドがexception 2に行くのかをどのように確認できますか?小さなブロックであれば問題ありませんが、いったん大きくなると、非常に読みにくくなります。
try{
doThing1();
doThing2();
doThing3();
doThing4();
doThing5();
doThing6();
doThing7();
doThing8();
doThing9();
} catch (Exception1 e){
} catch (Exception2 e){
}
以下はより明確です。
try{
doThing1();
} catch (Exception1 e){ [...] }
doThing2();
doThing3();
doThing4();
doThing5();
doThing6();
doThing7();
doThing8();
try{
doThing9();
} catch (Exception2 e){ [...] }
私の個人的な好みは、複数のcatchブロックがある場合とない場合がある1回の試行です。私の方法は、これが理にかなっている場合には十分に小さい傾向があります。実用化するには長すぎる場合は、おそらくリファクタリングについて考える必要があります。
Catchブロックに関する1つのこと:catchブロックがスタックトレースを出力またはログに記録して再スローする場合、メソッドシグネチャのthrows句に例外を追加してバブルアップさせる方が良いと思います。
単一のtry-catchブロックの方が優れているという上記の回答の一般的なコンセンサスに同意します。ただし、メソッドがこの質問を見るのに十分な長さになるまでには、おそらく長すぎます。また、例外処理がよりローカライズされている場合、そこから新しいメソッドを抽出する方が簡単かもしれません。それでも、あなたの最善の策は、元のメソッドで、理想的には単一のtry-catchブロックで例外をスローし、例外処理をそのままにしておくメソッドを抽出することだと思います。
非常に古い質問に見えます。しかし、私の答えは、最近ではJava 7が複数の例外とcatchブロックを追加するための新しい機能を追加したため、これは多くのコードを排除し、非常に興味深いようです。 linktry-with-resource の概念について説明します。
素晴らしい質問です。単一のtry-catchブロックを使用する必要があると言います。私の推論:メソッドを複数のtry-catchブロックに分割する理由がある場合は、メソッドを複数のメソッドにリファクタリングすることを検討する必要があります。
安全のために、すべての例外をスローするステートメントに対して個別のtry catchブロックを使用してください。1つのtryブロックにすべてを書き込むと、いずれかのステートメントが例外をスローすると、その下に記述されたステートメントは実行されません。
可能な限りコードの繰り返しを避けるようにしています。そのため、特定の種類の例外に対する応答が同じ場合は、一度キャッチします。
単一のtry-catchブロックが好きです。メソッドの長さが非常に長くなる場合は、モジュール方式のpuporseのためにメソッドを複数の内部メソッドに分割することを好みます。
また、これらの内部メソッドを再利用できる場合もあります。
このようにすれば、メンテナンスがずっときれいになり、改善されます。
それはあなたのコードロジックに依存します-あなたはいつでもプロセス(計算または何でも)を中断することができますか、または特定のステップで例外によって何らかのエラー状態が示された場合、フローとロールバック/通知/検証/何でも制御/する必要があります/必要があります。
単純なRSSクライアントを実装している場合、すべてのソケット関連コードを1つのブロックに保持できます。しかし、BitTorrentクライアントを作成している場合は、ステートマシンとより詳細な例外処理が必要になります。