web-dev-qa-db-ja.com

独自のJava例外クラスを作成するのはいつですか?

優れた設計/実践の観点から、Javaですでに事前定義されているものの代わりに、カスタムJava例外クラスを作成して使用する必要がありますか?

一部のアプリケーションでは、カスタム例外クラスがほとんど作成されていないか、作成されていない場合でも、常にネイティブJava例外を使用するように努力しています。一方、すべて。

ベストプラクティスは何ですか?

ありがとう!

36
PedroD

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

クライアントコードに役立つ情報がない場合は、新しいカスタム例外を作成しないでください。

次のコードの何が問題になっていますか?

_public class DuplicateUsernameException extends Exception {}
_

例外名を示す以外に、クライアントコードに有用な情報を提供していません。 Java例外クラスは他のクラスと同様であり、クライアントコードが詳細情報を取得するために呼び出すと思われるメソッドを追加できます。

次のような便利なメソッドをDuplicateUsernameExceptionに追加できます。

_public class DuplicateUsernameException
    extends Exception {
    public DuplicateUsernameException 
        (String username){....}
    public String requestedUsername(){...}
    public String[] availableNames(){...}
}
_

新しいバージョンには、リクエストされた名前を返すrequestedUsername()と、リクエストされたものと同様の利用可能なユーザー名の配列を返すavailableNames()という2つの便利なメソッドがあります。クライアントはこれらのメソッドを使用して、要求されたユーザー名が利用できないこと、および他のユーザー名が利用可能であることを通知できます。ただし、追加情報を追加しない場合は、次に標準例外をスローします:

_throw new IllegalArgumentException("Username already taken");
_
42
M. Abbas

優れた設計/実践の観点から、Javaですでに事前定義されているものの代わりに、カスタムJava例外クラスを作成して使用する必要がありますか?

既存の例外名でニーズが満たされない場合。

もう1つの設計上の懸念は、「適切な」例外クラスを拡張することです。たとえば、I/Oに関連する例外を発生させる場合、理想的にはIOException;を継承する必要があります。例外がプログラマーのエラーを示している場合、RuntimeExceptionを継承する必要があります(つまり、例外をチェックしないでください)。

カスタム例外を発生させると、例外をより正確に処理することもできます。たとえば、FooExceptionを継承するIOExceptionを定義している場合は、特別な処理を行うことができます。

_try { ... }
catch (FooException e) { ... } // Catch it _before_ IOException!
catch (IOException e) { ... }
_

また、例外は他のクラスと同様であるため、カスタムメソッドなどを追加できます。たとえば、ジャクソンはJsonProcessingExceptionを継承する IOException を定義しています。キャッチした場合は、 .getLocation() を使用して解析エラーの位置情報を取得できます。

10
fge

確かに、プログラムで例外を処理できると予想される場合-つまり、異なる例外タイプに対して個別のcatchステートメントを簡単に作成できます。

try{    
  buyWidgets();
}
catch(AuthenticationException ex)
{
  promptForLogin();
}
catch(InsufficientFundsException ex)
{
  promptToRefillAccount();
}
//let other types of exceptions to propagate up the call stack

上記がフロー制御の例外の不適切な使用を構成するかどうか

例外はif-elseステートメントよりもCPUが高くなりますが(主にスタックトレースの構築コストによる)、コストは相対的であり、特定のユースケースのコンテキストで評価する必要があります。すべてのコードがWebスケールで高速である必要はなく、一部の人々は条件の読み取りとテストが面倒だと感じています。たとえば、ほとんどすべてのトランザクションマネージャーは、例外を使用してcommit-rollback-retryイディオムを実装しています。 (例外をキャッチせずにトランザクションの再試行アスペクトを記述してみてください)

それとは別に、懸念の分離の原則を順守する必要があります。すべてのコードが考えられるすべての条件に対処する必要があるわけではありません。ウィジェットの購入中にログインしていないかどうかは例外的なケースで、アプリとアプリのコードベースの特定の場所に依存します。たとえば、ログインユーザー用の操作を含むサービスを作成できます。そのサービスのメソッドが認証を処理することは意味がありません-代わりに、これらのメソッドは呼び出しチェーンの早い段階でコードを期待してユーザーが認証されるようにし、そうでない場合は単に例外をスローします。したがって、ログインしていないメソッドの場合[〜#〜] [[##〜]は例外的なケースです。

6
Nikita

独自の例外を使用する場合は、コードベースにvalueを追加します。

とても簡単です。値は次のとおりです。

  • たとえば、すべての例外に共通のベースタイプがある場合など、より高いレベルでキャッチする方が簡単です。
  • 例外には追加データが含まれます(NLSキーは独自の例外に含まれているため、上位層はI18Nを考慮して人間のユーザーにメッセージを送信する方法を知っています)
2
GhostCat

アプリケーションにカスタム例外があると便利です。1つはアプリケーションのトップレベルのカスタム例外、もう1つはモジュール/パッケージレベルのカスタム例外です。アプリに特定の機能/操作があり、操作中に例外が発生したかどうかをユーザーに知らせる必要がある場合は、その操作のカスタム例外を追加することをお勧めします。問題のデバッグ/調査は簡単です。

1

エラーメッセージだけでなく、伝える必要のある情報がさらにある場合、カスタム例外を作成することがよくあります。

たとえば、特定のエラーコードまたは実際の値と期待値。これらは独自のゲッターを持つこともできるため、メッセージのテキストを変更した場合に壊れる可能性があるStringメッセージを解析することなく、プログラムでこれらのフィールドを取得できます。 (または、別の言語に翻訳します)

独自の例外を作成する場合は、APIがthrows IOExceptionしかし、実際にはMycustomIOExceptionをスローします。そうすれば、APIのユーザーは、必要がない限り、独自のカスタムバージョンについて知る必要がありません。

1
dkatzel