13

制御フローに例外を使用することは悪い習慣だと聞きました。これについてどう思いますか?

public static findStringMatch(g0, g1) {

    int g0Left = -1;
    int g0Right = -1;
    int g1Left = -1;
    int g1Right = -1;

//if a match is found, set the above ints to the proper indices
//...
//if not, the ints remain -1

        try {
            String gL0 = g0.substring(0, g0Left);
            String gL1 = g1.substring(0, g1Left);

            String g0match = g0.substring(g0Left, g0Right);
            String g1match = g1.substring(g1Left, g1Right);

            String gR0 = g0.substring(g0Right);
            String gR1 = g1.substring(g1Right);

            return new StringMatch(gL0, gR0, g0match, g1match, gL1, gR1);
        }
        catch (StringIndexOutOfBoundsException e) {
            return new StringMatch(); //no match found
        }

したがって、一致するものが見つからない場合、intは-1になります。これにより、部分文字列を取得しようとすると例外が発生しますg0.substring(0, -1)。次に、関数は一致するものが見つからないことを示すオブジェクトを返すだけです。

これは悪い習慣ですか?各インデックスを手動でチェックして、すべてが-1であるかどうかを確認することもできますが、それはもっと手間がかかるように感じます。

アップデート

try-catchブロックを削除し、次のように置き換えました。

    if (g0Left == -1 || g0Right == -1 || g1Left == -1 || g1Right == -1) {
        return new StringMatch();
    }

各変数が-1であるかどうかを確認するか、ブール値を使用foundMatchして追跡し、最後に確認するか、どちらが良いですか?

4

4 に答える 4

19

一般に、例外は高価な操作であり、その名前が示すように、例外的な条件です。したがって、アプリケーションのフローを制御するコンテキストでそれらを使用することは、実際には悪い習慣と見なされます。

具体的には、提供した例では、StringMatch コンストラクターに提供する入力の基本的な検証を行う必要があります。基本的なパラメーターの検証が失敗した場合にエラー コードを返すメソッドであれば、事前のチェックを避けることができますが、そうではありません。

于 2009-10-09T23:30:22.157 に答える
10

私はこれについていくつかのテストを行いました。最近のJVMでは、実際にはランタイムのパフォーマンスにそれほど影響を与えません(あるとしても)。デバッグをオンにして実行すると、処理速度が大幅に低下します。

詳細は以下をご覧ください

(パフォーマンスに影響を与えない場合でも、これは悪い習慣だと思います。何よりも、テストが困難になる可能性のある不十分なアルゴリズム設計を反映しています)

于 2009-10-10T00:13:17.873 に答える
6

はい、これは悪い習慣です。特に、例外を回避する手段がある場合(文字列にインデックスを付ける前に文字列の長さを確認してください)。try and catchブロックは、「通常の」ロジックを「例外的な」ロジックおよびエラーロジックから分割するように設計されています。あなたの例では、「通常の」ロジックを例外/エラーブロックに広げています(一致するものが見つからないことは例外ではありません)。また、誤用substringしているため、制御フローとして生成されるエラーを活用できます。

于 2009-10-10T00:10:14.553 に答える
6

プログラム フローは可能な限り直線的である必要があり (それでもアプリケーションはかなり複雑になるため)、標準の制御フロー構造を利用します。次にコードに触れる開発者はあなたではない可能性があり、制御フローを決定するために条件の代わりに例外を使用している非標準的な方法を (当然のことながら) 誤解しています。

私は現在、いくつかのレガシー コードのリファクタリング中に、この問題について少し異なる角度で戦っています。

このアプローチで私が見つけた最大の問題は、try/catch を使用すると、通常のプログラム フローが中断されることです。

私が取り組んでいるアプリケーション (これはあなたが適用したサンプルとは異なります) では、特定の結果 (たとえば、口座番号を探して見つからないなど) が発生したことをメソッド呼び出し内から通信するために例外が使用されます。これにより、クライアント側でスパゲッティ コードが作成されます。これは、呼び出し元のメソッド (例外的でないイベントまたは通常のユース ケース イベント中) が、呼び出し前に実行していたコードから抜け出し、catch ブロックに入るからです。これはいくつかの非常に長いメソッドで何度も繰り返されるため、コードが読み違えやすくなります。

私の状況では、メソッドは、真に例外的なイベントを除くすべての署名ごとに値を返す必要があります。例外処理メカニズムは、例外が発生したときに別のパスを取ることを目的としています (メソッド内から回復を試みて、正常に戻ることができるようにします)。

私の考えでは、try/catch ブロックを非常に厳密にスコープすれば、これを行うことができます。しかし、これは悪い習慣であり、非常に誤解しやすいコードにつながる可能性があると思います。これは、呼び出し元のコードがスローされた例外を「GOTO」タイプのメッセージとして解釈し、プログラム フローを変更するためです。このケースはこの罠に陥ることはありませんが、これを行うと、多くの場合、私が今住んでいる悪夢につながるコーディングの習慣が生じる可能性があるのではないかと心配しています.

そして、その悪夢は楽しいものではありません。

于 2010-02-19T18:14:29.963 に答える