14

これはおそらく幅広い質問であり、SOスタイルではありませんが、可能であれば、いくつかのヒントやガイドラインを入手したいと思います。

私はいくつかのレガシーコードを調べていて、3または4レベル下にネストされた例外を除いてメソッドを持っているその一部を見つけました。
これは通常の慣行と見なされますか、それとも可能な限りそのようなコードスタイルを避けるべきですか?回避する必要がある場合、例外処理のコストの増加と読みやすさの低下以外に、どのような悪影響がありますか?これを回避するためにコードをリファクタリングする一般的な方法はありますか?

4

8 に答える 8

16

私は個人的に次のイデオロギーを好みます

エイリアンの例外をラップする

「エイリアン」例外は、JavaAPIまたはサードパーティライブラリによってスローされる例外です。言い換えれば、あなたが制御しない例外です。

すべてのエイリアン例外をキャッチし、それらを適切なアプリケーション固有の例外でラップすることをお勧めします。エイリアン例外が独自の例外に変換されると、その例外を任意の方法で伝播できます。

チェックされた例外を再スローすると、乱雑になる可能性があります

アプリケーションがチェックされた例外を使用する場合、元の例外を再スローすることは、それを再スローするメソッドもそれを宣言する必要があることを意味します。

呼び出し階層の最上位に近づくほど、より多くの例外がスローされたと宣言されます。すべてのメソッドを宣言して例外をスローしない限り。ただし、そうする場合は、チェックされていない例外を使用することをお勧めします。これは、コンパイラの例外チェックによるメリットが実際には得られないためです。

これが、アプリケーション固有ではない例外をキャッチし、それらをアプリケーション固有の例外でラップしてから、それらを呼び出しスタックに伝播することを好む理由です。

ラッピングのガイドライン:例外が発生するコンテキストは、例外自体の場所と同じくらい重要な場合があります。アプリケーション内の特定の場所には、さまざまな実行パスを介して到達できる場合があり、実行パスは、エラーが発生した場合、その重大度と原因に影響を与える可能性があります。

例外をコールスタックに伝播するときにコンテキスト情報を例外に追加する必要がある場合は、アクティブな伝播を使用する必要があります。つまり、コールスタックを上る途中のさまざまな関連する場所で例外をキャッチし、関連するコンテキスト情報を追加してから、再スローまたはラップする必要があります。

public void doSomething() throws SomeException{

    try{

        doSomethingThatCanThrowException();

    } catch (SomeException e){

       e.addContextInformation(“more info”);
       throw e;  //throw e, or wrap it – see next line.

       //throw new WrappingException(e, “more information”);

    } finally {
       //clean up – close open resources etc.
    }

}
于 2012-12-24T09:46:47.557 に答える
3

チェックされた例外は、可能であればスタックに伝播したり、チェーンしたりしないでください。メソッドがチェックされた例外をスローしている場合、その呼び出し元はそれを処理することになっています。呼び出し元がそれを処理していない場合、呼び出し元に伝播すると、全体的な複雑さが増します。

3層の例:Dao、Service、Controller

DAOレイヤーはDAOExceptionをスローしますサービスレイヤーはDAOExceptionをコントローラーに公開しないでください。代わりに、コントローラーが処理する必要のある関連するBuinessExceptionをスローする必要があります。

于 2012-12-24T09:27:46.447 に答える
3

例外処理は、フロー制御を処理するための高価な方法になる傾向があります(確かにC#とJavaの場合)。

例外オブジェクトが構築されると、ランタイムは非常に多くの作業を実行します。スタックトレースをまとめたり、例外が処理される場所を特定したりします。

フロー制御ステートメントがフロー制御に使用される場合、拡張する必要のないメモリとCPUリソースのこれらすべてのコスト。

さらに、セマンティックの問題があります。例外は例外的な状況であり、通常のフロー制御ではありません。通常のプログラムフローとしてではなく、予期しない/例外的な状況を処理するために例外処理を使用する必要があります。そうしないと、キャッチされない例外によって通知がはるかに少なくなるためです。

これらの2つとは別に、他の人がコードを読むという問題があります。このような方法で例外を使用することは、ほとんどのプログラマーが期待することではないため、可読性とコードの理解度が低下します。「例外」を見ると、何か悪いことが起こった、通常は起こらないはずの何かが起こったと思います。したがって、この方法で例外を使用することは、単純に混乱を招きます。

以下のリンクをご覧ください

例外処理:Java1.4の一般的な問題とベストプラクティス-pdf

例外を通常の制御フローとして使用してみませんか?

例外処理のベストプラクティス

エラー処理

グーグルリンクス氏

于 2012-12-24T09:43:51.477 に答える
3

私はいくつかのレガシーコードを調べていて、3または4レベル下にネストされた例外を除いてメソッドを持っているその一部を見つけました。

これは通常の慣行と見なされますか、それとも可能な限りそのようなコードスタイルを避けるべきですか?

これは、この方法で例外を処理するために必要なプロセスではありません。非常に特定の例外(チェックまたはエイリアン例外)を実際に処理する必要があり、その例外を処理するための特定の情報を取得するためにオーバーヘッドを無視できるようになるまで、アプリケーションのオーバーヘッドが増加するためです。 。

回避する必要がある場合、例外処理のコストの増加と読みやすさの低下以外に、どのような悪影響がありますか?

前述したように、例外に関する特定の情報は取得されません。ネストされた例外処理を使用しない場合(上位ハンドラーに追加情報をスローする)、いくつかの厳しい例外に代わって特定のアクションを実行する場合と実行しない場合があります。ただし、ネストされた場合は、その特定の状況を処理することでアクションを実行できます。

これを回避するためにコードをリファクタリングする一般的な方法はありますか?

あなたがあなたが望むことをし、深刻なバグがない、不十分に因数分解されたプログラムを持っているなら、神のためにそれを放っておいてください!バグを修正したり機能を追加したりする必要がある場合は、作業中に遭遇したコードを容赦なくリファクタリングします。カスタム例外ハンドラーの例外クラスをオーバーライドし、問題を処理するためにいくつかの追加機能を追加します。

オーバーライドするメソッドは、オーバーライドされたメソッドによって宣言されたものよりも新しい、またはより広いチェック済み例外をスローしてはなりません。たとえば、FileNotFoundExceptionを宣言するメソッドは、FileNotFoundExceptionのサブクラスでない限り、SQLException、Exception、またはその他の非実行時例外を宣言するメソッドでオーバーライドすることはできません。

これがお役に立てば幸いです。

于 2012-12-28T07:02:55.313 に答える
0

ネストの例外を廃止する必要があります。そもそも例外を連鎖させないようにするか、(選択的に)ラップを解除してから、ネストされた例外をスタックのさらに上に再スローする必要があります。

于 2012-12-22T09:03:25.140 に答える
0

レガシーコードの処理について私はあなたがトピックをカバーしている本を見る​​のをお勧めします:http: //www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052 あなたは全体を通過する必要さえありません本、ただ今あなたに関係するものを見てください。

また、グッドプラクティスに関する優れた本は次のとおりです。http: //www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882/ref=sr_1_1? +コード

ネストされた例外を処理する場合の最善のアプローチは、コードをリファクタリングし、チェックされた例外の代わりにランタイムを使用し、必要に応じてそれらを処理することです。このようにして、コードはより読みやすく、保守が容易になります。

于 2012-12-24T09:23:20.493 に答える
0

それはビジネスロジックに依存します。例外自体に対してアクションを実行することも、発信者までそれを伝播して、発信者が望むアクションを発信者に任せることもできます。

たとえば、例外を処理しないサードパーティのAPIはたくさんありますが、メソッドから例外をスローするため、APIユーザーは必要に応じてアクションを実行できます。

eqoracleJDBCドライバー。Driver.getConnection()は例外をスローします。これで、呼び出し元/APIユーザーは必要に応じてそれを処理できます。スタックトレースを印刷するだけの場合もあれば、管理者に注意を促すように通知する場合もあります。または、アプリケーションを黙って終了する場合もあります。

于 2012-12-24T09:23:46.267 に答える
0

2つのアプローチがあります:

To generate a separate exception for each event.
To create a generic exception and describe what caused it 

最初のアプローチでは、さまざまなイベントを処理するためのさまざまなコードを記述できますが、多くのExceptionクラスを記述する必要があり、場合によっては多すぎる可能性があります。

2番目のアプローチはより簡潔ですが、さまざまな状況に対処するのが困難になります。

プログラミングでは非常に頻繁に発生するため、最適なソリューションは途中で、個別の例外を生成することと、他の場合に1つの例外を使用することのバランスを取ります。

この場合の経験則は、個別のコードで具体的に処理する例外に対して個別のExceptionクラスを生成することです。

何を投げるかと同様に、何を捕まえるかを制御する必要があります。キャッチブロックには2つのアプローチを使用できます。

すべてのための単一のキャッチブロック。例えば:

catch (Throwable e) {
throw new CommandExecutorException(e);
}

多くのcatchブロックは、例外ごとに1つです。例えば:

} catch (ClassCastException e1) {
 ...
} catch (FileNotFoundException e) {
... 
} catch (IOException e) {
...
}

最初のアプローチは非常にコンパクトですが、基本的にすべての例外を同じケースでグループ化します。これは、すべての例外が等しく管理され、同じことを行う状況でのみ役立ちます。このアプローチは、キャ​​ッチされる例外を制御できないため、一般的には推奨されません。これにより、困難なバグが発生することもありますが、これも見つけるのが困難です。

2番目のアプローチでは、より多くのコード行が必要ですが、発生した例外に応じてさまざまな操作を実行できます。このアプローチはより柔軟ですが、場合によっては、例外処理のためにメソッドが非常に長くなることがあります。

于 2012-12-24T10:11:02.423 に答える