3

私は例外について広範な調査を行いましたが、まだ迷っています。やっていいこと、やらなかったことを知りたいです。

また、次の例について専門家の意見をお聞かせください。

public void myprocess(...) {
    boolean error  = false;

    try {

        // Step 1
        try {
            startProcess();
        } catch (IOException e) {
            log.error("step1", e);
            throw new MyProcessException("Step1", e);
        }

        // Step 2
        try {
            ...
        } catch (IOException e) {
            log.error("step2", e);
            throw new MyProcessException("Step2", e);
        } catch (DataAccessException e) {
            log.error("step2", e);
            throw new MyProcessException("Step2", e);       
        }

        // Step 3
        try {
            ...
        } catch (IOException e) {
            log.error("step3", e);
            throw new MyProcessException("Step3", e);
        } catch (ClassNotFoundException e) {
            log.error("step3", e);
            throw new MyProcessException("Step3", e);       
        }

        // etc.

    } catch (MyProcessException mpe) {
        error = true;       
    } finally {
        finalizeProcess(error);
        if (!error) {
            log.info("OK");
        } else {
            log.info("NOK");
        }           
    }
}
  1. グローバルな try...catch...finally を管理するために、各ステップで個人的な例外 (MyProcessException) をスローしても問題ありませんか?
  2. ステップごとに既知の各例外を管理してもよろしいですか?

ご協力ありがとうございました。


編集1:

このような良い習慣はありますか?メッセージを取得してグローバル catch に直接ログインし、上位レベルで try...catch(Exception)....

目的は、ステップが失敗した場合に停止し、プロセスを終了することです (エラーかどうかに関係なく)。

In Controller

public void callProcess() {
    try {
        myprocess(...);
    } catch (Exception e) {
        log.error("Unknown error", e);
    }   
}

In Service

public void myprocess(...) {
    boolean error  = false;

    try {

        // Step 1
        try {
            startProcess();
            log.info("ok");
        } catch (IOException e) {
            throw new MyProcessException("Step1", e);
        }

        // Step 2
        try {
            ...
        } catch (IOException e) {
            throw new MyProcessException("Step2", e);
        } catch (DataAccessException e) {
            throw new MyProcessException("Step2", e);       
        }

        // Step 3
        try {
            ...
        } catch (IOException e) {
            throw new MyProcessException("Step3", e);
        } catch (ClassNotFoundException e) {
            throw new MyProcessException("Step3", e);       
        }

        // etc.

    } catch (MyProcessException mpe) {
        error = true;       
        log.error(mpe.getMessage(), mpe);           
    } finally {
        finalizeProcess(error);
        if (!error) {
            log.info("OK");
        } else {
            log.info("NOK");
        }           
    }
}

ありがとうございました。


編集2:

下位レベルで (Exception e) をキャッチし、個人的な例外をスローするのは本当に悪い習慣ですか?

4

6 に答える 6

2

上記の例では、独自のカスタム例外をスローしても問題ない場合があります。

さまざまな種類 (SQL、ファイルの読み取り/書き込みなど) のデータ アクセス オブジェクト (DAO) があるとします。各 DAO がストレージ メカニズムに固有の例外 (SQL 関連の例外など) をスローすることは望ましくありません。CouldNotStoreExceptionそれがクライアントが取り組んでいる抽象化のレベルであるため、私は彼らに a をスローしてもらいたいです。SQL 関連またはファイル関連の例外をスローすると、内部の仕組みが明らかになり、クライアントは特に関心がありません。彼らは、読み取り/書き込み操作が機能したかどうかを知りたいだけです。

元の例外を原因として使用して、カスタム例外を作成できます。そうすれば、問題に関する元の情報を失うことはありません。

上記では、あなたが行ったように、各ステップで各例外を処理しないでしょう。例外の後で処理を続行できない場合は、コード ブロック全体を例外処理ブロックでラップするだけです。可読性が向上し、例外をキャッチしてから (後で) 処理ステータスをチェックして、通常どおり続行できるかどうかを確認する必要がなくなります (これを行わないと、1 つの例外に対して多くの例外が生成されます)。元の問題であり、それは役に立ちません)。

catch {}例外ごとに複数のブロックが何かを追加するかどうかを検討します (それぞれに異なることをしていますか?)。Java 7では、複数の例外クラスを 1 回のキャッチで処理できることに注意してください{}(Java 6 を使用していることは承知していますが、完全を期すためにこれを書き留めておきます)。

最後に、チェックされた例外とチェックされていない例外について考えたいと思うかもしれません。

于 2013-02-06T10:28:16.140 に答える
2

一般的なルールは存在しません。必要に応じて異なります。個人的な例外をスローしたり、既知の各例外を管理したりできます。

しかし、注意してください、あなたが何を望むかが重要です。

try{
   exec1();
   exec2(); // if exec1 fails,  it is not executed
}catch(){}

try{
   exec1();
}catch(){}

try{
   exec2(); // if exec1 fails,  it is  executed
}catch(){}
于 2013-02-06T10:28:48.493 に答える
1

例外メカニズムの要点は、処理コードを減らしてグループ化することです。C など、例外のない言語に典型的なスタイルでそれらを処理しています。すべてのオカレンスには個別の処理ブロックがあります。

ほとんどの場合、最良のオプションは、メソッド コード全体をキャッチオールで囲むことです。

try {
 .... method code ...
} 
catch (RuntimeException e) { throw e; } 
catch (Exception e) { throw new RuntimeException(e); }

これが適切でない唯一の場合は、特定の処理コードを挿入する場合、または後で明確に処理されるカスタム例外をラップする場合です。

特にあなたの場合、ほとんどの例外は失敗IOExcption以外の何ものでもなく、それをログに記録し、アプリケーションを安全なポイントに戻し、さらにリクエストを処理できるようにする以外に処理はありません。同じ処理コードを何度も繰り返している場合は、それが間違っていることを示しています。

非常に重要なルールの 1 つは、ハンドルまたは再スローのいずれかです。両方を行うことはありません。それがあなたの例で行っていることです: ロギングと再スローの両方です。ほとんどの場合、再スローされた例外はコール スタックのさらに上に捕捉され、再度ログに記録されます。生成されたログ ファイルを読み取るのは悪夢ですが、残念なことに非常によく知られています。

于 2013-02-06T10:28:45.443 に答える
0

ここに、例外処理パターン/アンチパターンへのリンクがいくつかあります。

行う:

しないでください:

独自の例外の作成については、API、フレームワーク、または別の再利用可能なコードを作成する場合に確かに役立ちますが、通常のアプリケーションでは、より議論の余地があり、個人的には既存の例外に固執することをお勧めします。

于 2013-02-06T10:35:38.120 に答える
0

それはあなたのニーズに依存すると思います...

step1 が失敗しても step2 が正しく実行できる場合は、step1 を個別に試行/キャッチできます。
それ以外の場合は、すべてのステップを 1 つの try/catch ブロックにグループ化し、個々のステップが失敗したときにログ メッセージが生成されるようにします。そうすれば、コードを散らかさずに、何が問題なのかを知ることができます

既知の各例外をキャッチしても問題ないため、発生した例外とその理由をログに記録できます。

于 2013-02-06T10:30:44.953 に答える
0
int step = 0;

try
{
    step = 1;
    ...
    step = 2;
    ...
    step = 3;
    ...
}
catch (Exception1 e)
{
    log ("Exception1 at step " + step);
    throw new MyException1 ("Step: " + step, e);
}
catch (Exception2 e)
{
    log ("Exception2 at step " + step);
    throw new MyException2 ("Step: " + step, e);
}
...
于 2013-02-06T10:29:52.437 に答える