web-dev-qa-db-ja.com

ThrowableをJava

Javaでは、Throwableのまったく新しいサブタイプを作成できます。例:

_public class FlyingPig extends Throwable { ... }
_

さて、めったに、私はこのようなことをするかもしれません:

_throw new FlyingPig("Oink!");
_

そしてもちろん他の場所:

_try { ... } catch (FlyingPig porky) { ... }
_

私の質問は次のとおりです。

  • これは悪い考えですか?もしそうなら、なぜですか?
    • それが悪い考えである場合、このサブタイプを防ぐために何ができたでしょうか?
    • それは(私が知る限り)予防できないので、どのような大惨事が発生する可能性がありますか?
  • これがそれほど悪い考えではないのなら、なぜですか?
    • _extends Throwable_できるという事実から、どうすれば何か役に立つものを作ることができますか?

提案されたシナリオ#1

私が本当にこのようなことをしたいと思ったシナリオには、次のプロパティがあります。

  • 「イベント」は、が最終的に発生するものです。 予想です。それは間違いなくErrorではなく、いつ発生するかについてはException- alは何もありません。
    • expectedであるため、catchが待機します。何もすり抜けることはありません。 catch general Exceptionおよび/またはErrorへの試行から「エスケープ」することはありません。
  • 「イベント」は非常にまれに発生します。
  • それが発生すると、通常、深いスタックトレースがあります。

だから、おそらく今私が言おうとしていることは明らかです:FlyingPigは徹底的な再帰検索の結果です。

検索対象は存在します。検索スペースである大海原でそれを見つけるだけです。検索プロセスは長いものになるため、例外処理の比較的高価なコストはごくわずかです。実際、_boolean isFound_フラグを使用する代わりの従来の制御フロー構造は、検索プロセス全体で、おそらく再帰のすべてのレベルで継続的にチェックする必要があるため、よりコストがかかる可能性があります。このチェックは99.99%の確率で失敗しますが、終了条件を伝播することが絶対に必要です。ある意味で、有効であるのに対し、チェックは非効率です!

探しているオブジェクトが見つかったときにthrowを単にFlyingPig-するだけで、_boolean isFound_フラグの管理でコードを乱雑にする必要はありません。その点でコードがクリーンになるだけでなく、この省略によりコードの実行速度が上がる可能性があります。

要約すると、選択はこれら2つの間です。

  • 従来の制御フローアプローチ
    • 継続的にチェックされる_boolean isFound_を使用します
    • 99.99%の確率で、チェックは「無駄」です。これは、まだfalseであるためです。
    • 最終的にtrueになると、繰り返しを停止し、最初の呼び出しに適切に巻き戻すことができることを確認する必要があります。
  • FlyingPigアプローチ
    • _boolean isFound_を気にしないでください。
    • 見つかった場合は、throw new FlyingPig(); expectedなので、catchがあります。
    • booleanフラグの管理、続行する必要があるかどうかの無駄なチェック、再帰を手動で巻き戻すための簿記などはありません。

質問:

  • 例外を(ab)使用するこの手法は有効ですか? (名前はありますか?)
  • 有効な場合、_FlyingPig extends Throwable_である必要がありますか、それともExceptionで問題ありませんか? (その状況について例外的なことは何もありませんが?)
28

それは本当に悪い考えだと思います。 ErrorExceptionをキャッチすると、考えられるすべての例外をキャッチしたことを前提に、多くのコードが実装されます。そして、ほとんどのチュートリアルと教科書はあなたに同じことを教えてくれます。 Throwableの直接サブクラスを作成することにより、あらゆる種類のメンテナンスと相互運用性の問題が発生する可能性があります。

Throwableを拡張する正当な理由は考えられません。代わりにExceptionまたはRuntimeExceptionを拡張してください。

[〜#〜] edit [〜#〜]-OPの提案されたシナリオ#1への応答。

例外は、「通常の」フロー制御を処理するための非常にコストのかかる方法です。場合によっては、例外を作成、スロー、およびキャッチするために実行される数千の追加命令について話します。受け入れられている知識を無視し、例外的でないフロー制御に例外を使用する場合は、Exceptionサブタイプを使用します。 Throwableのサブタイプは何も達成しないため、何かを偽装しようとすると、「例外」ではなく「イベント」であると宣言します。

ただし、例外をエラー、間違い、間違ったものなどと混同するのは間違いです。そして、Exceptionのサブクラスを使用して、「エラー、間違い、間違ったものなどではない例外的なイベント」を表すことには、何も悪いことはありません。重要なのは、イベントがexceptionalである必要があるということです。つまり、異常な、非常にまれにしか発生しない、.。

要約すると、FlyingPigはエラーではないかもしれませんが、それをExceptionのサブタイプとして宣言しない理由はありません。

32
Stephen C

例外を(ab)使用するこの手法は有効ですか? (名前はありますか?)

私の意見では、それは良い考えではありません:

  • 驚き最小の原則 に違反します。特に例外がない場合は、コードが読みにくくなります。
  • 例外のスローは、Javaでは非常にコストのかかる操作です(ただし、ここでは問題にならない可能性があります)。

例外は フロー制御には使用されません である必要があります。この手法に名前を付ける必要がある場合は、コードの臭いまたはアンチパターンと呼びます。

参照:

有効な場合、FlyingPigThrowableを拡張する必要がありますか、それともExceptionで問題ありませんか? (その状況について例外的なことは何もありませんが?)

catchThrowableをキャッチするだけでなく、ExceptionだけでなくErrorもキャッチしたい場合がありますが、それはまれです。 、人々は通常Throwableをキャッチしません。しかし、私はあなたがしたい状況を見つけるのに失敗しますthrowThrowableのサブクラス。

また、Throwableを拡張しても、見た目が悪くなることはなく "exception-al"、見栄えが悪くなると思います。

結論として、本当に何かをスローしたい場合は、Exceptionのサブクラスをスローします。

参照:

8
Pascal Thivent

HotSpotアーキテクトのJohnRoseからのブログ投稿は次のとおりです。

http://blogs.Oracle.com/jrose/entry/longjumps_considered_inexpensive

これは、フロー制御の例外を「乱用」することについてです。ユースケースは少し異なりますが、..要するに、スタックトレースが作成されないように例外を事前に割り当て/複製すると、非常にうまく機能します。

この手法は、クライアントから「隠されている」場合には正当であると思います。 IE、FlyingPigがライブラリを離れることができないようにする必要があります(すべてのパブリックメソッドは、ライブラリをスローしないことを推移的に保証する必要があります)。これを保証する1つの方法は、チェックされた例外にすることです。

Throwableを拡張する唯一の理由は、catch(Exception e)句を含むコールバックをユーザーが渡せるようにし、結果が無視されるようにするためだと思います。私はそれを買うことができます...

7
rjw

org.junit.Testアノテーションには、Noneを拡張するThrowableクラスが含まれ、expectedアノテーションパラメータのデフォルト値として使用されます。

4
Stephen Denne

FlyingPigをErrorとExceptionの両方と区別して、どちらのサブクラスとしても適さないようにすることができるのであれば、それを作成することに根本的な問題はありません。

私が考えることができる最大の問題は、実用的な世界にあります。Java.lang.Exceptionをキャッチする正当な理由がある場合があります。あなたの新しいタイプのスローアブルは、致命的ではない可能性のあるすべての問題を抑制する(またはロギング、ラッピングなど)という合理的な期待をすべて持っていたtry-catchブロックを通り過ぎて飛ぶでしょう。

逆に、n Java.lang.Exceptionを正当に抑制している古いシステムでメンテナンスを行っている場合は、それをごまかすことができます。 (実際に適切に修正するための時間に対する誠実な訴えは否定されます)。

4
Affe

Play!framework は、リクエスト処理にこのようなものを使用します。リクエスト処理は多くのレイヤー(ルーティング、ミドルウェア、コントローラー、テンプレートレンダリング)を通過し、最後のレイヤーでレンダリングされたHTMLは スロー可能にラップされます そしてスローされます。これは最上位のレイヤーがキャッチ、アンラップ、送信します。クライアントに。したがって、関係する多くのレイヤーのメソッドはいずれも、応答オブジェクトを明示的に返す必要はありません。また、伝播および変更するために、引数として応答オブジェクトを渡す必要もありません。

私は細部について少し大ざっぱです。 Playのコードを確認できます。詳細についてはフレームワーク。

2
Abhinav Sarkar

この質問が進化するにつれて、私は元の質問のポイントを誤解していることがわかります。したがって、他の回答のいくつかはおそらくより適切です。同様の質問をしている他の人にも役立つ可能性があるため、この回答はここに残しておき、質問に対する回答を検索しているときにこのページを見つけます。

Throwableを拡張して、カスタム例外をスロー(および処理)できるようにすることには何の問題もありません。ただし、次の点に注意する必要があります。

  • 可能な限り最も具体的な例外を使用することは素晴らしい考えです。これにより、呼び出し元はさまざまなタイプの例外を異なる方法で処理できます。例外のクラス階層は覚えておくことが重要です。したがって、カスタム例外は、例外にできるだけ近い別のタイプのThrowableを拡張する必要があります。
  • Throwableの拡張は高レベルすぎる可能性があります。代わりに、ExceptionまたはRuntimeException(または例外をスローする理由に近い低レベルの例外)を拡張してみてください。 RuntimeExceptionとExceptionの違いに注意してください。
  • Exception(またはExceptionのサブクラス)をスローするメソッドの呼び出しは、例外を処理できるtry/catchブロックでラップする必要があります。これは、制御不能な状況(ネットワークがダウンしているなど)が原因で問題が発生することが予想される場合に適しています。
  • RuntimeException(またはそのサブクラス)をスローするメソッドの呼び出しは、例外を処理できるtry/catchブロックでラップする必要はありません。 (確かにそうなる可能性がありますが、そうである必要はありません。)これは、実際には予期されるべきではない例外のためのものです。

したがって、コードベースに次の例外クラスがあるとします。

_public class Pig extends Throwable { ... }
public class FlyingPig extends Pig { ... }
public class Swine extends Pig { ... }
public class CustomRuntimeException extends RuntimeException { ... }
_

そしていくつかの方法

_public void foo() throws Pig { ... }
public void bar() throws FlyingPig, Swine { ... }
// suppose this next method could throw a CustomRuntimeException, but it
// doesn't need to be declared, since CustomRuntimeException is a subclass
// of RuntimeException
public void baz() { ... } 
_

これで、次のようなこれらのメソッドを呼び出すコードを作成できます。

_try {
    foo();
} catch (Pig e) {
    ...
}

try {
    bar();
} catch (Pig e) {
    ...
}

baz();
_

bar()を呼び出すと、PigFlyingPigの両方がSwineを拡張するため、Pigをキャッチできることに注意してください。これは、どちらかの例外を処理するために同じことをしたい場合に役立ちます。ただし、別の方法で処理することもできます。

_try {
    bar();
} catch (FlyingPig e) {
    ...
} catch (Swine e) {
    ...
}
_
2
pkaeding