ループ内にネストされている場合、try-catchステートメントのネストは依然としてコードの匂いですか?


8

try-catchステートメントをネストするとコードの臭いになることがよくあると聞いたので、この状況が例外かどうか疑問に思います。そうでない場合、リファクタリングするためのいくつかの良い方法は何でしょうか?

私のコードは次のようになります:

try{
    X x = blah;
    otherStuff;
    for (int i = 0; i < N; i++){
        try{
            String y = Integer.toString(i);
            f(x);
        }
        catch(Exceptions1 e1){
            System.err.println(... + y + ...);
            System.exit(0);
        }
}
catch(Exceptions2 e2){
    ...
}

Exceptionsここではマルチキャッチを示すために使用しています。

e2初期化xおよび実行によってスローされた例外をキャッチするために使用されますotherStuff。理想的には、2つの行だけをtry-catchで囲んでいたはずですがx、ループ内で使用し、try-catchの外側でnullに初期化することによって引き起こされる「未使用の割り当て」警告を回避したいと考えました。

e1e2反復の詳細に関する情報をユーザーに提供したいため、ループ内にキャッチブロックが必要だったため、マルチキャッチされませんでした。

回答:


6

場合e2キャッチは、あなたが言うように、唯一の初期化でエラーをキャッチするxと、やってotherStuffあなたは別々のメソッドに抽出できます。これにより、ロジックが適切に分離され、意味のある名前をに付けることができますotherStuff

public X Foo() {
    try{
        X x = blah;
        otherStuff;

        return x;
    }
    catch(Exceptions2 e2){
        ...
    }
}

public void Bar() {    
    X x = Foo();
    for (int i = 0; i < N; i++){
        try{
            String y = Integer.toString(i);
            f(x);
        }
        catch(Exceptions1 e1){
            System.err.println(... + y + ...);
            System.exit(0);
        }
    }
}

それは私が私の機能にエラーが引くのではなく、まだ、とにかく起こる内部キャッチ、のエイリアスを提供して分離させ、この答えは、私の状況に最も理にかなって
Weasemunk

7

例外が発生するかどうかに関係なく、内部ループ全体を処理するつもりがない限り、コードは基本的に以下と同等です。

try{
    X x = blah;
    otherStuff;
    for (...){ 
       f(x)
    }
}
catch(Exceptions1 e1){
    ...
}
catch(Exceptions2 e2){
    ...
}

ネストは必要ありません。

それでも内部例外処理が必要な場合は、内部例外とそれを囲むメソッドを新しいメソッドにリファクタリングします。これには、内部ループを処理する他の方法を考えるように強いるという追加の利点もあります。例外の多くがスローされる場合、例外はパフォーマンスの面で非常に高価になる可能性があります。


どういう意味かわかります。私の状況をさらに詳しく示すために、いくつかの詳細を追加しました。内側のループでは、反復iに依存するyの値を使用したいと思います(実際には、それぞれにaを使用していますが、これによりポイントが渡ります)。私の内側のキャッチは、キャ​​ッチされたときにyの値について何かを言いますが、外側のキャッチはループから独立しています。ネストを回避することはできますか、それとも、ループに依存する情報を提供するという私の決定に縛られますか?
イタチ

私はまだ内部ループを独自のメソッドにリファクタリングすると思います。そこでは例外を除いて何でも好きなことができます。
Robert Harvey

おかげで、私はあなたの回答を@Martin Brendanの回答と組み合わせて、クリーンなソリューションを作成しました。
イタチサンク

3

私はあなたの質問についていくつかの観察があります:

  1. 指定した例では、例外はまったく必要ありません。文字列yを確認し、エラーをログに記録して、ループを終了するだけで済みます。yが無効であり、ログに記録する必要があることについて、何も例外はありません。この場合に例外を使用しているという事実は、コードのにおいを示しています。

  2. マルチキャッチ例外は、実際には、大量のコードをラップし、問題が発生する可能性のあるものをキャッチするために使用されることを意図していません。これらは、コードの単一のセクションが一連の異なる例外を生成する可能性がある場合に、例外を区別するのに役立つことを目的としています。一種の「すべてをキャッチする」アプローチとしてマルチキャッチ例外を使用しているため、これはコードのにおいを示しています。

  3. 要素の1つで例外が見つかった場合でも、ループの残りの部分を繰り返し続けるつもりでない限り、ループ内にtry catchを配置しても意味がありません。サンプルコードは、1つのアイテムが例外的な場合にループを終了することを計画していることを示しています。

私はあなたが次のようなものでより良いかもしれないと思います:

try
{
     var x = blah;
     DoStuff();
     foreach(var i in icollection) // i is an int
     {
          var y = SomethingDependentOnI(i);

          // check y for explicit exceptional states
          if (IsSomethingWrongWithY(y))
               throw new Exception1(y);
     }
}
catch (Exception1 e1)
{
}
catch (Exception2 e2)
{
}

これははるかに明確ですが、それでも上記の問題に悩まされています。


コメントをありがとう。1 + 2は実際のコードに関してはあまり関係がありませんでしたが、ループ内でのスローに関するあなたの見方は理にかなっていると思います
Weasemunk
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.