java.lang.Exception を使用するのではなく、どの時点で独自の例外クラスを作成しますか? (常に? パッケージ外で使用される場合のみ? 高度なロジックを含める必要がある場合のみ? など...)
10 に答える
「新しい例外を作成することで、私や私のコードを使用する開発者にどのような利点がありますか?」という少し異なる質問を自問する必要があると思います。それがあなたや他の人々に与える唯一の利点は、例外を処理できることです。それは明白な答えのように思えますが、実際にはそうではありません。合理的に回復できる例外のみを処理する必要があります。スローした例外が本当に致命的なエラーである場合、なぜ開発者にそれを誤って処理する機会を与えるのでしょうか?
詳細な議論:カスタム例外: いつ作成する必要がありますか?
理由 1:
特定のものをキャッチする必要があります。呼び出しコードが特定の例外条件に対処する必要がある場合は、例外を区別する必要があり、Java はさまざまなタイプの例外を区別するため、独自に記述する必要があります。
基本的に、誰かが書かなければならない場合:
catch(ExistingException e) {
if({condition}) {
{ some stuff here}
}
else {
{ different stuff here}
}
}
おそらく、特定の拡張機能を書きたいと思うでしょう。catch 例外の一致は、条件、IMHO よりも明確です。
覚えておいてください: 新しい Exceptionは RuntimeException のサブクラスにすることができます
理由 2:
API の統合。インターフェイスを作成し、いくつかの実装がある場合、さまざまな非RuntimeExceptionsがスローされたさまざまなAPIを呼び出す可能性があります。
interface MyInterface {
void methodA();
}
class MyImplA {
void methodA() throws SQLException { ... }
}
class MyImplB {
void methodA() throws IOException { ... }
}
本当に MyInterface.methodA に SQLException と IOException をスローさせたいですか? おそらく、可能性のある例外をカスタム Exception でラップすることは理にかなっています。これもRuntimeExceptionになる可能性があります。または、RuntimeException 自体でさえ...
私は信じている:
catch (Exception e) {
...
}
... は避けるべきアンチパターンです。エラーをログに記録し、アプリケーション全体が終了するのを防ぐために、アプリケーションのどこかに一元化された広範なキャッチが必要な場合がありますが、それらが散らばっているのは悪いことです。
どうして:
try {
if(myShape.isHidden()) {
throw new Exception();
}
// More logic
} catch (Exception e) {
MyApp.notify("Can't munge a hidden shape");
}
これを試すと、コーディング エラーにより、myShape が null になります。ランタイムが myShape を逆参照しようとすると、NullPointerException がスローされます。このコードは、null ポインターを報告する必要があるときに、非表示の形状を報告します。
独自の例外を作成するか、API で適切に特化された例外を見つけてください。Exception や RuntimeException の拡張が面倒というわけではありません。
自分の例外を他の人とは異なる方法で扱いたい場合。自分のものをキャッチして他の人のものを伝播したい場合、または他の誰かのものをキャッチして自分のものを伝播したい場合、または両方をキャッチしたいがそれらを別の方法で扱いたい場合は、例外用に別のクラスを定義します。両方を伝播するか、両方をキャッチすることによって (そして、キャッチされた例外に対していずれかの方法で同じことを行うことによって)、それらをすべて同じように扱いたい場合は、標準クラスを使用します。
言語ランタイムまたはライブラリに既存の例外がある場合は、それを使用するか、それ以外の場合は独自に作成し、適切に文書化すると、99% のケースで機能するはずです。
ソフトウェアは意味を捉えます。
既存の例外をスローする理由はほとんどありません。JVM が既にそれを行っています。あなたの例外のバージョンは実際には正確ではなく、「例外」をスローすることも意味がありません。
あなたがDataFormatException
書いた解析アルゴリズムが原因である可能性があります。ただし、これはまれです。
プログラムが例外的な状況に遭遇した場合、それはほとんどの場合、そのプログラムに固有のものです。例外的な状況を既存の例外に強制的に適合させるのはなぜですか? それがあなたのプログラムに固有のものである場合、それは...まあ...それは固有のものです。そのように名前を付けます。
ただし、一意のメッセージごとに一意の例外クラスを提供しないでください。1 つの例外クラスに、多数のバリアント メッセージとサポート詳細を含めることができます。
Java に変換された Python の経験則は、パッケージ レベルで一意の例外を定義することです。[Python では、「モジュール」レベルでの例外が提案されていますが、これは正確には Java に変換されません。]
常に共通の例外クラスを使用して開始し、それを特別に処理する必要があると思われる場合は、それを変更します。
初めてメソッドを作成するときは、例外を通過させます。
処理する必要がある例外がある場合は、スローで定義するか、ランタイム例外にラップするか、独自のスロー例外をラップすることができます。多くの場合、私は実行時例外を好みます。スロー定義の定義は、API の観点から必要になるまで避ける必要があります。
後で、一部の呼び出し元で例外に対して特定の処理を行う必要があると思われる場合は、戻って新しい例外を作成します。
ポイントは、何が必要かを知る前に余計な作業をしないことです。
オブジェクト/クラス/メソッドに問題があった場合に java.lang.Exception を具体的にスローすることは想像できません。これはあまりにも一般的です。独自の Exception クラスを作成しない場合は、API に少なくともより具体的な Exception タイプが必要であるように思えます。
例外が API に関連する場合は、Java API からの例外を使用します。ただし、独自の API に固有の例外的な状況が発生した場合は、例外を作成します。たとえば、min と max の 2 つのプロパティと invariant min <= max を持つ Range オブジェクトがある場合、例外 InvalidRangeException を作成します。
私がコードを書いているとき、これは私が自分自身の条件の1つに違反したために例外が発生したのか、それともJava APIから何かに違反したのかを知っているので役立ちます.
ほとんどの場合、独自の例外クラスを作成しても意味がありません。
初心者のプログラマーは、エラーの種類をより示す名前を使用できるように、独自の例外クラスを作成する傾向があります。そのため、FTPInitializationException、DAOFactoryException などのクラスが見つかりますが、そのような例外は標準の例外とは異なる方法で処理されていません。これは明らかに避けるべきアンチ パターンです。