3

私はここで Java フロー制御と例外処理についてしばらく研究してきましたが、一般的に受け入れられているルールは次のとおりです。

  1. フロー制御に例外処理を使用しない
  2. クライアントが回復することを期待しない限り、チェック例外を避ける (これは、クライアントに例外を強制的に処理させ、例外から回復しようとする可能性があることを示す良い方法です)。

一般的なルールに加えて、私は従おうとしています:

  1. doSomething() が「何らかの処理」に失敗した場合、呼び出し元にこれを通知する必要があります
  2. メソッドは、1 つのことを行うことに関係する必要があります。

これにより、場合によってはミックスが悪くなります。メソッド内でチェックされた例外をキャッチし、どこでもブール値を返し、連続する呼び出しを継続的にチェックする必要があることを発見しました。

if(doA()){
  if(doB()){
    if(doC()){ 
      // only here do I know it's good
    }else{
      // I know C failed
    }
  }else{
    // I know B failed
  }
}else{
  // I know A failed
}

一部の部分で 5 ~ 6 個のネストされた if-else が深くなっており、かなり醜いです。ブール変数の束を管理して、何が機能し、何が機能しなかったかを追跡することは言うまでもありません。

何かアドバイス?ここは「goto」が受け入れられる場所でしょうか?

4

4 に答える 4

5

doA()、、、doB()およびを調べる必要がありdoC()ます。それらが失敗する可能性がかなり低い場合は、失敗したときに例外をスローします。

try {
  doA();
  doB();
  doC();
} catch (FailureException e) {
  // handle failure
}

不当な失敗の例はたくさんあります、、、IOExceptionなどIllegalParameterException

それらが合理的に失敗する可能性が高い場合

if (!doA()) {
  // handle A's failure
  return;
}
if (!doB()) {
  // handle B's failure
  return;
}
if (!doC()) {
  // handle C's failure
  return;
}

合理的な失敗の例は、Javaではあまり強調されていません。いくつかの例には、read()これ以上読むものがないときに-1を返すことが含まれます。あなたのdoA()名前が実際に近い場合は、おそらく試行の成功を示すものをattemptA()返すのが適切です。boolean考えてみadd(...)てください。インターフェースでは、結果が変更された場合に返さaddAll(...)れます。CollectionstrueCollection

gotoコードをレビューするとき、コードが「どこから来たのか」を知ることは事実上不可能であるため、従来の方法はほとんどの言語で適切な選択ではありません。入る前の状態に関するこの知識の欠如はgoto、ブロックに入る前に一貫した環境を保証することを不可能にしgotoます。ちなみに、これが伝統的なものがJavaで利用できない理由でgotoあり、限られた継続のみが利用可能gotoです。

ネストが不十分な構造からネストが少ない構造に変換するには、いくつかのリファクタリング手法を使用します。

if(doA()){
  if (doB()) {
    if (doC()) { 
      // only here do I know it's good
    } else {
      // I know C failed
    }
  } else {
    // I know B failed
  }
} else {
  // I know A failed
}
return;

と同等です

if (doA()) {
  if (doB()) {
    if (doC()) { 
      // only here do I know it's good
    } else {
      // I know C failed
    }
  } else {
    // I know B failed
  }
  return;
} else {
  // I know A failed
  return;
}

これは

if (!doA()) {
  // I know A failed
  return;
} else {
  if (doB()) {
    if (doC()) { 
      // only here do I know it's good
    } else {
      // I know C failed
    }
  } else {
    // I know B failed
  }
  return;
}

「IknowAfailed」のコードにリターンが含まれている場合は、doA()真の条件でコードが以下のコードに該当することを心配する必要はありません。したがって、次のように下部ブロックをプロモートできます。

if (!doA()) {
  // I know A failed
  return;
}
if (doB()) {
  if (doC()) { 
    // only here do I know it's good
  } else {
    // I know C failed
  }
} else {
  // I know B failed
}
return;
于 2011-04-13T19:39:21.083 に答える
1

はい。戻りコードではなく例外を使用します。必要に応じて、例外を独自にラップすることができます。

例外的な条件で、フロー制御に例外を使用することは完全に合理的です。通常の推奨事項は、通常のフロー制御での使用を避けることです。

于 2011-04-13T19:36:50.740 に答える
0

「クライアントが回復することを期待しない限り、チェックされた例外を使用しない」というルールは間違っていると思います。呼び出し元がまったく回復しないようにするのはかなり一般的ですが、代わりに例外を呼び出し元に渡し、場合によっては例外を別の何かに変換します。

于 2011-04-13T19:37:21.607 に答える
0

The State Patternを使用します。そうすることで、現在の状態から移行できる可能性のある状態のみを確認できるため、コードが読みやすくなります

于 2011-04-13T19:57:05.410 に答える