効率的なtry / catchブロックの使用法?


21

catchブロックは、ロジックの記述、つまりフロー制御などの処理に使用する必要がありますか?または、例外をスローするためだけに?コードの効率や保守性に影響しますか?

catchブロックにロジックを記述した場合の副作用(ある場合)は何ですか?

編集:

catchブロック内にロジックを記述したJava SDKクラスを見てきました。例(java.lang.Integerクラスから抜粋したスニペット):

        try {
            result = Integer.valueOf(nm.substring(index), radix);
            result = negative ? new Integer(-result.intValue()) : result;
        } catch (NumberFormatException e) {
            String constant = negative ? new String("-" + nm.substring(index))
                                       : nm.substring(index);
            result = Integer.valueOf(constant, radix);
        }

EDIT2

私は、例外の中に例外的なケースのロジックを書くことの利点としてそれを数えるチュートリアルを行っていました:

例外を使用すると、コードのメインフローを記述し、例外的なケースに対処することができます。

catchブロックでロジックを作成する場合としない場合の具体的なガイドラインはありますか?


12
@Coder少し一般化しすぎていると思います。特に、既存のAPIの多くでは回避できないためです。
CodesInChaos

8
@Coder:Javaの例外は、正当なコードフローの一部である問題を通知するためのメカニズムとしてよく使用されます。たとえば、ファイルを開こうとして失敗した場合、Javaライブラリは例外をスローすることでそれを通知します。これは、ファイルを開くことにつながるAPIには、エラーを返す他のメカニズムがないためです。
JeremyP

4
@Coder依存。IOを実行するとき、またはほとんど常に正しくフォーマットされている複雑なデータを解析するとき、エラーを示すために例外をスローすると、コードがずっときれいになります。
CodesInChaos

1
@Codedはい、execptionは、要求されたことを実行できないことを通知するメソッドのためにあります。ただし、フロー制御には例外を使用しないでください。そのため、C#にはスローしないint.TryParseメソッドもあります。
アンディ

1
@Coder:それはまったくのゴミです。あるレベルのコードで例外的であるものは、別のレベルで例外的ではない場合があります。たとえば、続行する前にエラーまたはデバッグ情報を提示または追加することもできます。
-DeadMG

回答:


46

あなたが引用する例は、貧弱なAPI設計によるものです(Stringを解析して例外をキャッチすることを除いて、Stringが有効な整数であるかどうかをチェックする明確な方法はありません)。

技術レベルでは、throwとtry / catchは制御フロー構造であり、コールスタックをジャンプできます。呼び出しスタックを上にジャンプすると、ソース内で互いに近接していないコードが暗黙的に接続されますが、これは保守性に悪影響を及ぼします。したがって、それを行う必要がある場合にのみ使用する必要があり、代替手段はさらに悪いです。選択肢が悪化している広く受け入れられている場合は、エラー処理である(必要性がチェックされ、手動でコールスタックの各レベルを渡されることを特別なリターンコード)。

代替案の方が悪い場合(そして実際にそれらすべてを慎重に検討している場合)、制御フローにthrowおよびtry / catchを使用することは問題ありません教義は判断の良い代用品ではありません。


1
+1、良い点。エラーメッセージの準備やエラーログなど、一部の処理はキャッチで有効であると思われます。db接続や(.NET)COM参照などの高価なリソースの解放は、Finallyブロックに追加できます。
-NoChance

@EmmadKareem私はリソースを解放することを考えましたが、通常、エラー状態がなくても、いずれかの時点でリソースを解放する必要があります。したがって、あなたは自分自身を繰り返すかもしれません。もちろん、ログメッセージの準備は受け入れられます。
スカーフリッジ

@MichaelBorgwardt APIの設計はそれほど悪くはないと思います(ただし、改善される可能性はあります)。無効な文字列を解析しようとすることは明らかにエラー条件であり、したがって、まさにあなたが述べた「広く受け入れられているケース」です。合意された、文字列が構文的に正しいかどうかを判断する方法は便利です(これがより良い可能性がある場所です)。ただし、実際の解析の前に全員にこのメソッドを強制的に呼び出させることはできないため、エラーを処理する必要があります。実際の結果とエラーコードを混在させるのは不快なので、それでも例外がスローされます。しかし、実行時の例外かもしれません。
スカーフリッジ

3
その最後の文に+1。
FrustratedWithFormsDesigner

2
@scarfridge:私はあなたと完全に同意:)ブールを返すisInteger(String)メソッドが存在しない場合は、すべて私が「不良APIの設計」を意味する
マイケルBorgwardt

9

これは、言語とパラダイムに依存する傾向があるものです。

私の仕事の大部分はJava(そしてC ++でさえ)で行われます。例外は例外的な条件にのみ使用する傾向があります。Stack Overflowには、Javaの例外のパフォーマンスオーバーヘッドに関する質問いくつかあります。ご覧のとおり、それは決して無視できるものではありません。コードの可読性や保守性など、他の懸念事項もあります。適切に使用すると、例外はエラー処理を適切なコンポーネントに委任できます。

ただし、Pythonでは、許可よりも許しを求める方が簡単だという考えが支配的です。Pythonコミュニティでは、これはEAFPとして知られています。これは、Cスタイル言語の「飛ぶ前に見る」(LBYL)アプローチとは対照的です。


2
例外を伴うオーバーヘッドに言及するための+1。私は.NETを実行し、(少なくとも私のマシンでは)他の通常の操作と比較して、場合によってはそれがかかる期間までに例外が発生しようとしていると感じることさえできました。
-NoChance

2
@EmmadKareemデバッガーが接続されている場合のみ。デバッガーを使用せずに、1秒あたり数千個をスローできます。
CodesInChaos

@CodeInChaos、あなたは正しいです。どうやって知っているのでしょうか、実行時にまったく取得しないようなクリーンなコードを書く:)
NoChance

@EmmadKareemネットワークアプリケーションの記述方法に応じて、接続またはプロトコルの障害は例外を伴って処理されます。このようなアプリケーションでは、些細なDoS攻撃を避けるために、例外を適度に高速にする必要があります。
CodesInChaos

@CodeInChaos、これは知っておくと良いことです。最後のコメントで冗談を言っていました。
-NoChance

9

これは、try / catchブロックについて考える最良の方法ではありません。try / catchブロックについて考える方法はこれです。障害が発生しました。この特定の障害に対処するのに最適な場所です。これは、コードの次の行である可能性があります。呼び出しチェーンの20レベル上の可能性があります。どこにいても、それはあるべき場所です。

catchブロックが行うことは、エラーとそれに対してできることによって異なります。単純に無視できる場合もあります(不変データのないスクラッチファイルを削除できない場合)、関数の戻り値をtrueまたはfalseに設定するために使用される場合(javaのint解析メソッド)、場合によってはプログラムを終了します。これらはすべてエラーに依存しています。

理解すべき重要な部分は次のとおりです。catch block ==これに対処する方法を知っています。


6

Catchブロックは、例外を処理するためにのみ使用する必要があり、制御フローには使用しないでください。フローを管理するために例外を使用する場合は、前提条件を確認することをお勧めします。

例外を伴うフローの処理は遅く、意味的に正しくありません。


4
あなたの言っていることは知っていますが、例外はプログラムフローを処理することだけです
Max

catchブロックにロジックを作成する場合としない場合に特定のガイドラインはありませんか?
HashimR

4
Javaの数値パーサーとテキストフォーマッターは、問題のある例外の使用法の有名な例です。前提条件(文字列が解析可能な数値を表す)を確認する唯一の合理的な方法は、解析を試みることです。実際には?例外が意味的に正しくないと見なされても、例外をキャッチしてフローを管理する必要があります。
ジョナスプラッカ

@JoonasPulakkaあなたのコメントは、数値パーサーとテキストフォーマッターがこの質問に対するフルサイズの答えとして資格がある思います
ブヨ

5

catchブロックは、ロジックの記述、つまりフロー制御などの処理に使用する必要がありますか?または、例外をスローするためだけに?コードの効率や保守性に影響しますか?

最初に、「例外は例外的な条件に使用する必要がある」という概念を忘れてください。また、許容できないパフォーマンスを発揮するコードを入手し、問題がどこにあるかを知るために測定するまで、効率について心配するのを止めてください。

コードは、アクションが条件なしで単純なシーケンスで続くときに理解するのが最も簡単です。例外は、通常のフローからエラーチェックを削除することにより、保守性を向上させます。実行が99.9%の時間、50%の時間、または20%の時間の通常フローに従うかどうかは関係ありません。

関数が値を返すことができない場合、プロシージャが期待されるアクションを完了できない場合、またはコンストラクターが使用可能なオブジェクトを生成できない場合に例外をスローします。これにより、プログラマは関数が常に使用可能な結果を​​返し、プロシージャが常に要求されたアクションを完了し、構築されたオブジェクトが常に使用可能な状態にあると想定できます。

例外処理コードで見られる最大の問題は、プログラマーがtry / catchブロックを書き込むべきではないときに書き込むことです。たとえば、ほとんどのWebアプリケーションでは、データベース要求が例外をスローした場合、コントローラーで実行できることは何もありません。最高レベルの汎用的なcatch句が1つあれば十分です。その後、コントローラーコードは、ディスクがクラッシュした、データベースがオフラインになっているなどの可能性を大いに無視できます。


1

キャッチブロックは、コードロジックの記述に使用しないでください。エラーの処理にのみ使用する必要があります。たとえば、(1)割り当てられたリソースをクリーンアップし、(2)有用なメッセージを出力し、(3)正常に終了します。

例外が悪用され、望ましくないgoto影響を引き起こす可能性があるのは事実です。しかし、だからといって役に立たないわけではありません。ときに適切に使用され、彼らはあなたのコードの多くの側面を向上させることができます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.