web-dev-qa-db-ja.com

例外の伝播に関するガイドライン(Javaの場合)

Javaでの例外の伝播に関するガイドラインはありますか?

いつメソッドシグネチャに例外を追加しますか?たとえば、重要なプログラムリソースが欠落している場合にのみ例外がスローされ、最上位でしか処理できない場合、この例外を使用するすべてのメソッドから、エラーメソッドを使用するすべてのメソッドに例外を伝達しますか?

良い習慣はありますか?悪い習慣はありますか?

漠然としていて申し訳ありませんが、例外に関するプログラミングスタイルに関するいくつかの(一般的な)アドバイスを探しています。

42
wen

過去に私を助けてきたガイドラインは次のとおりです。

  • メソッドが例外を処理できない場合に例外をスローします、さらに重要なことに、呼び出し側が処理する必要があります。この良い例は、サーブレットAPIに存在します-doGet()およびdoPost()は、リクエストが正しく読み取られなかった特定の状況でServletExceptionまたはIOExceptionをスローします。これらのメソッドはどちらも例外を処理する立場にありませんが、コンテナはそうです(ほとんどの場合、50xエラーページが表示されます)。
  • メソッドが例外を処理できない場合は例外をバブルします。これは上記の結果ですが、例外をキャッチする必要があるメソッドに適用できます。キャッチされた例外をメソッドで正しく処理できない場合は、バブリングすることをお勧めします。
  • すぐに例外をスローします。これは曖昧に聞こえるかもしれませんが、例外のシナリオが発生した場合は、例外のスローに適していると見なされるポイントまで、エラーコードを介してエラーの処理を試みるのではなく、元のエラーのポイントを示す例外をスローすることをお勧めします。 。つまり、例外処理とエラー処理の混在を最小限に抑えるようにしてください。
  • 例外をログに記録するか、例外をバブルしますが、両方を実行しないでください。例外をログに記録すると、多くの場合、例外スタックが完全に巻き戻されたことを示します。これは、例外のバブリングが発生していないことを示します。そのため、両方を同時に実行することはお勧めできません。これは、デバッグでイライラする経験になることが多いためです。
  • Java.lang.Exception (チェックされた例外)のサブクラスを使用して、呼び出し元を除いて例外を処理する場合。これにより、呼び出し元が例外を処理しない場合、コンパイラはエラーメッセージをスローします。ただし、これは通常、開発者がコードで例外を「飲み込む」原因になります。
  • Java.lang.RuntimeException (未チェックの例外)のサブクラスを使用して、プログラミングエラーを通知します。ここで推奨される例外クラスには、 IllegalStateExceptionIllegalArgumentExceptionnsupportedOperationException などが含まれます。ここでも、NullPointerException(mostly常に投げるのは悪い習慣です)。
  • 例外クラス階層を使用して、さまざまな層にわたって例外に関する情報を伝達します。階層を実装することにより、呼び出し元での例外処理動作を一般化できます。たとえば、InvalidCustomerException、InvalidProductExceptionなどのサブクラスがいくつかあるDomainExceptionのようなルート例外を使用できます。ここでの注意点は、例外シナリオをそれぞれ別個の例外として表すと、例外階層が急速に爆発する可能性があることです。
  • 処理できない例外をキャッチしないようにします。かなり明白ですが、多くの開発者はJava.lang.ExceptionまたはJava.lang.Throwableをキャッチしようとします。サブクラス化されたすべての例外をキャッチできるため、「グローバルな」例外クラスがキャッチされたときのアプリケーションの実行時の動作は、あいまいになることがよくあります。結局のところ、OutOfMemoryErrorをキャッチしたくありません。そのような例外をどのように処理すればよいのでしょうか。
  • 例外を慎重にラップします。例外を再スローすると、例外スタックがリセットされます。元の原因が新しい例外オブジェクトに提供されていない限り、それは永久に失われます。例外スタックを保持するには、元の例外オブジェクトを新しい例外のコンストラクターに提供する必要があります。
  • 必要な場合にのみ、チェックされた例外をチェックされていない例外に変換します。例外をラップする場合、チェックされた例外をラップして、チェックされていない例外をスローすることができます。これは、特定の場合、特に現在実行中のスレッドを中止することが目的である場合に役立ちます。ただし、他のシナリオでは、コンパイラチェックが実行されないため、これは多少の痛みを引き起こす可能性があります。したがって、チェックされた例外をチェックされていない例外として適合させることは、盲目的に行われることを意図していません。
53
Vineet Reynolds

メソッドはできるだけ早く処理する必要がありますが、それは理にかなっている必要があります。例外がメソッドによってスローされても意味がなく、処理できない場合は、それを別の例外にラップして、この新しい例外をスローします。

例外についての悪い習慣は、それらすべてをキャッチすることです(それはポケモンではなく、Java!)なので、catch(Exception e)またはより悪いcatch(Throwable t)を避けてください。

2
Colin Hebert