Java= Webアプリケーションを開発しています。これは、3層のアーキテクチャです。
web>サービス>リポジトリ。
私は多くの例外を作成することを考えています-それぞれが個々のエラーに固有であり、ビジネスロジックが存在するサービスレイヤーで、ビジネスエラーに関連付けられている特定の例外をスローしたいと考えています。
そして、Webレイヤー(それがフロントエンドに近いスタックのさらに上)で、それをキャッチし、それに応じて処理しています。
誰かが私に言った、これは悪い習慣であり、代わりに単一の一般的なビジネス例外を1つだけスローするようにアドバイスしたので、このようにしないでください。これを聞いたときの私の反応は、大学で学んだすべてのこと、過去の経験、および一般的な技術書で読んだものに反するというものでした。
Javaで複数のカスタム例外をスローするのは悪い習慣ですか?
いいえ、それは良い習慣です。
複数の例外が(少し)悪い考えである唯一の状況は、個別の例外をキャッチする可能性が(絶対に!)まったくない場合です。つまり、きめの細かい例外は機能的な目的には役立ちません。しかし、私の意見では、あなたがその主張をすることができれば、おそらくあなた/あなたのチームがJavaを使用している方法に何か問題があると思います。そして、反対の議論は、複数のカスタム例外を賢明に使用すると、APIを文書化するのに役立つということです...たとえ実行時にcatch-log-and-bail-out以上のことをするつもりがない場合でもです。
これは、多くのカスタム例外が常に良いことだと言っているのではありません。
行き過ぎて、すべてに対して個別の例外を作成する場合、おそらく不要な複雑さを追加しています。 (多くの場合、異なる例外メッセージで十分です。)
カスタム例外に適切な継承階層がない場合、後悔する可能性があります。 (適切に設計された階層により、例外の「クラス」をキャッチしたり、例外をスローするようにメソッドを宣言したりできます。これにより、コードが単純になります。)
Javaで複数のカスタム例外をスローするのは悪い習慣ですか?
一般的に言えば、いいえ。なぜそれが必要なのでしょうか。
すべてと同じように:抽象化はあなたの友達です。
CustomerNotFound
例外とProductNotFound
例外が必要ですか?それともあなたの要件はもう少しabstractNotFoundException
?コンテキストは、何が欠けていたかを判断するのに役立ちます。それらを持つために異なる例外を持つことはナンセンスです。
アプリケーションの各層にカスタムの例外が必要ですか?例外は、意図したアクションが何らかの理由で失敗したことを報告する方法です。
たとえば、サービスレイヤーにデータの取得を要求するコントローラーがあり、DAレイヤーにDBからの値の読み取りを要求するコントローラーがあるとします。 resultsetはemptyです。サービスは空の結果セットを取得し、サービスが通信するNotFoundException
をスローします。結果がないためにアクションが失敗します。
たとえば、コントローラーが従業員の給与計算を行うサービスが必要であるとします。そして、サービスは[〜#〜] id [〜#〜]123456
を使用して従業員の給与計算を行うように要求され、次に従業員を取得するようにサービスに要求しますが、従業員が見つかりました。
これに対処するには2つの方法があります。
1)DAレイヤーでNotFound
例外をスローし、それをpayroll-serviceサービスでキャッチし、PayrollServiceException
をラップしてNotFoundException
を再スローしますメッセージExmployee could not be found
2)DAレイヤーでNotFound
例外をスローし、それをpayroll serviceでキャッチせず、代わりに上のレイヤーでキャッチします。
(1)の情報では、missing従業員が原因でアクションが失敗したというので、(2)に行きます。
ここに座っているSpringアプリケーションを見ていると、数十のカスタム例外があります。これの多くは、Springを使用すると、例外がフレームワークレイヤーまで泡立ち、フレームワークによって対応するHTTPステータスコードに適切に変換されるためです。
例外の木があることに注意してください。これらにはたまたま共通のルートがあり、トップレベルのGenericBusinessException(抽象的ではありません)をスローすることができます。 that例外を実行すると、誰がそれを実行したかに関する情報メッセージがログに記録され、静的分析でそれを見るとpmd警告も表示されることに注意してください。借金し、今すぐ単純な例外をスローして、他の例外のための他のすべての作業ではなく、ドアからそれを取得します。
例外の処理全体がそれをログに記録するだけの場合、これらすべての例外を書き込むことは時間の無駄だと考えるかもしれません。そして、いくつかの状況では、私は同意するでしょう。ただし、あるレベルで例外ごとに異なる処理を行う場合、別の方法として、例外のフィールドに列挙型を投げるか、文字列としてGenericBusinessExceptionを入力し、実際には何もしません。
カスタム例外は意味を追加し、コーダーがコードの意図をより明確に表現できるようにします。これにより、メンテナーは(例外が推論できる方法で使用されている場合)アプリケーションのフローをより迅速に追跡できます。この点で、それらは非常に優れており、有益です。
私の経験では(Java開発者です)それはis悪い習慣です。コードのにおいではありませんが、ほとんどの場合、あなたの毎日の仕事で。
ファイルを読み込もうとして、おそらくFileNotReadableException
をスローするアプリケーションを考えてみてください。しばらくすると、アクセス権が不十分なためにファイルを読み取れない可能性があることに気づきました。職業はなんですか?例外の名前を変更します-いいえ、まだ使用されている可能性があります。サブタイプFileNotReadableBecauseOfAccessRightsException
?を追加しますか?ええと、これはむしろ2つのエラーです-読み取り可能ではなく+アクセス権ですが、根本的な原因は権利の問題です。したがって、InsufficientAccessRightsException
をクラスツリーの別の場所に追加します。その場合、元の例外がキャッチされたコードを、その2つの異なるタイプ(open-closed-principleの違反)から変更する必要もあります。などなど...そして何が得られるのですか? ...メッセージのある例外とは対照的ですか?静的型安全性。例外のコンテキストでは、タイプミスを防ぐのにのみ役立ちます。開発者は依然として間違った例外タイプを使用する可能性があります(例:EntryNotFoundException
ではなくFileNotReadableException
)。
Dwozが言ったように:例外は単なるクラスです。
私の経験では、いくつかの例外で十分です。あなたが表現したいのはエラーメッセージです-いくつかのメッセージについては、文字列フィールドを持つ1(実行時)例外のみが必要です。すべての例外は、可能な限り最上位のレイヤー(または必要に応じてそれより前)でデフォルトのエラーハンドラーによってキャッチされます。
通常のメッセージに加えて、ファイルシステムパス、ユーザー名、デバイスID、分散システムでのエラーをより簡単に追跡するためのUUIDなどの情報を保存する必要がある場合があります。これらの目的のために、カスタムを作成することをお勧めします例外クラス。
Amonが言ったように、経験則は次のとおりです:librariesの場合は(一部の)例外を使用し、(web-)アプリケーションの場合できるだけ少ない
例外は結局単なるクラスであり、Exceptionのフレーバーを拡張したり、Throwableを実装したりしながら、独自のインスタンスフィールドとメソッドを持つことができることを思い出してください。
エラー条件ごとに例外を定義することは、クラスにとっては不適切なレベルの特異性である可能性があると思うので、私はこれを言います。また、具体性を提供する詳細を含めることができます。
一般に、スローされた例外を処理するさまざまな方法ごとに例外タイプを作成します。