Javaのチェックされた例外は、長年にわたっていくつかの悪い報道を受けています。わかりやすい兆候は、それが文字通り世界で唯一の言語であることです(GroovyやScalaのような他のJVM言語でさえも)。SpringやHibernateなどの著名なJavaライブラリもそれらを使用しません。
私は個人的に(レイヤー間のビジネスロジックで)それらの1つの用途を見つけましたが、そうでなければ私はかなりアンチチェックされた例外です。
私が気付いていない他の用途はありますか?
Javaのチェックされた例外は、長年にわたっていくつかの悪い報道を受けています。わかりやすい兆候は、それが文字通り世界で唯一の言語であることです(GroovyやScalaのような他のJVM言語でさえも)。SpringやHibernateなどの著名なJavaライブラリもそれらを使用しません。
私は個人的に(レイヤー間のビジネスロジックで)それらの1つの用途を見つけましたが、そうでなければ私はかなりアンチチェックされた例外です。
私が気付いていない他の用途はありますか?
回答:
まず第一に、他のプログラミングパラダイムと同様に、適切に機能するために適切に行う必要があります。
以下のために私がチェック例外の利点は、Javaランタイムライブラリの作者はすでに私が合理的に処理することができると期待されるかもしれない一般的などのような問題は私のために決めたということです呼び出しポイント(トップレベルのキャッチプリントとは対照的に、ダイブロック)およびこれらの問題の処理方法をできるだけ早く検討します。
チェック例外は、エラー回復をできるだけ早く考えさせることでコードをより堅牢にするため、私はチェック例外が好きです。
より正確には、私に基づいて、それは非常に早いと言ってとは対照的に、プロセス内の奇妙なコーナーケースを検討するために私を強制的に、これは、より堅牢な私のコードを作る「ファイルがまだ存在していない場合おっと、私のコードは処理されません」本番環境でエラーが発生した場合、コードを修正して処理する必要があります。既存のコードにエラー処理を追加することは、メンテナンスを開始するときとは対照的に、最初からすぐに行うのではなく、重要なタスクになる可能性があり、したがって費用がかかります。
これは、不足しているファイルが致命的なものであるということかもしれないとプログラムが炎にクラッシュするようになりますが、その後、あなたがしてその決定を下します
} catch (FileNotFoundException e) {
throw new RuntimeException("Important file not present", e);
}
これは、非常に重要な副作用も示しています。例外をラップする場合は、スタックトレースに説明を追加できます。これは非常に強力です。たとえば、欠落していたファイルの名前、このメソッドに渡されたパラメーター、またはその他の診断情報に関する情報を追加でき、その情報は頻繁にスタックトレースに存在するためです。プログラムがクラッシュしたときに取得します。
人々は「これをデバッガで実行するだけで再現できる」と言うかもしれませんが、私は非常に頻繁に生産エラーを後で再現できず、本質的にあなたの仕事がかかっている非常に厄介な場合を除き、生産でデバッガを実行できないことを発見しました。
スタックトレースの情報が多いほど良いです。チェック済みの例外は、その情報を早期に取得するのに役立ちます。
編集:これはライブラリデザイナーにも当てはまります。私が日常的に使用しているライブラリの1つには、多くの多くのチェック済み例外が含まれており、それらを使用することで面倒さが少なくなるように設計することができます。
チェック例外が実際にどのようになったかを説明する2つの良い答えがあります。(両方に+1。)しかし、意図は実際に価値があるので、理論的に彼らが意図したものを調べることも価値があります。
チェックされた例外は、実際には言語の型安全性を高めることを目的としています。整数乗算のような簡単な方法を考えてください。このメソッドの結果タイプは整数であると考えるかもしれませんが、厳密に言えば、結果は整数例外またはオーバーフロー例外です。メソッドの戻り値の型として整数の結果を単独で考慮すると、関数の全範囲が表現されません。
この観点から見ると、チェックされた例外が他の言語への道を見つけられなかったと言うのは厳密には真実ではありません。Javaが使用した形式をとっていません。Haskellアプリケーションでは、代数的データ型を使用して、関数の正常な完了と失敗した完了を区別するのが一般的です。これは例外ではありませんが、それ自体、意図はチェック例外とほとんど同じです。これは、APIコンシューマーに、成功した場合と失敗した場合の両方を処理するように強制するように設計されたAPIです。例えば:
data Foo a =
Success a
| DidNotWorkBecauseOfA
| DidNotWorkBecauseOfB
これは、成功のほかに関数に2つの追加の結果があることをプログラマに伝えます。
IMO、チェックされた例外は、かなりまともなアイデアであったかもしれないものの欠陥のある実装です(完全に異なる状況の下で-しかし、実際には現在の状況では良いアイデアでさえありません)。
良い考えは、プログラムがスローする可能性のあるすべての例外がキャッチされることをコンパイラーに確認してもらうことです。実装の欠陥は、それを行うために、Javaが、チェックされた例外をスローするように宣言されているものを呼び出すクラスで、例外を直接処理することを強制することです。例外処理の最も基本的な考え方(および利点)の1つは、エラーが発生した場合、特定のエラーとは関係のないコードの中間層を許可し、その存在そのものを完全に無視できることです。チェックされた例外(Javaで実装されている)はそれを許可しないため、最初から例外処理の主要な(主な?)利点を破壊します。
理論的には、プログラム全体でのみ強制的にチェック例外を有効にすることができます。つまり、プログラムを「構築」しながら、プログラム内のすべての制御パスのツリーを構築します。ツリー内のさまざまなノードには、1)生成可能な例外、および2)キャッチ可能な例外で注釈が付けられます。プログラムが正しいことを確認するために、ツリーを歩いて、ツリー内の任意のレベルでスローされたすべての例外がツリー内のより高いレベルでキャッチされたことを確認します。
彼らがそれをしなかった理由は(とにかく推測する)、そうするのは耐え難いほど難しいだろうということです-実際、私は誰もがそれを非常に単純なもの(「おもちゃ")言語/システム。Javaの場合、動的なクラスロードなどにより、他の多くの場合よりもさらに難しくなります。さらに悪いことに、(Cのようなものとは異なり)Javaは(少なくとも通常は)静的にコンパイル/実行可能ファイルにリンクされていません。つまり、エンドユーザーが実際にプログラムのロードを開始して実行するまで、この種の強制を実行しようとするグローバルな認識をシステム内にまったく持たないということです。
その時点で施行を行うことは、いくつかの理由で非実用的です。まず第一に、せいぜい起動時間を延ばすことであり、これはすでにJavaに関して最も大きな、最も一般的な不満の1つです。第二に、良いことをするためには、プログラマーがそれを修正するのに十分早い段階で問題を検出する必要があります。ユーザーがプログラムをロードしているとき、あまり良いことをするには遅すぎます-その時点での唯一の選択肢は、例外があるかもしれないという機会に、問題を無視するか、プログラムのロード/実行をまったく拒否することですそれは捕まえられませんでした。
そのままでは、チェック例外は役に立たないよりも悪いですが、チェック例外の代替設計はさらに悪いです。チェック例外の基本的な考え方は良いもののように思えますが、実際にはあまり良くなく、たまたまJavaに特に適していません。通常、リフレクション/動的クラスロードのような完全な実行可能ファイルにコンパイル/リンクされるC ++のようなものについては、もう少しチャンスがあります(ただし、率直に言って、同じ種類の混乱なしに正しく強制することもできます)現在のJavaの原因は、おそらく現在の最新技術を超えているでしょう。
UnexpectedException
から派生した型で自動的にラップされる必要がありますRuntimeException
。「スロー」と「予期しない」は矛盾しないことに注意してください。foo
スローBozException
して呼び出した場合bar
、それはbar
スローすることを期待しているという意味ではありませんBozException
。
それらは、プログラマーの迷惑をかけ、例外の飲み込みを促すのに非常に適しています。例外の半分のポイントは、エラーを処理するための適切なデフォルトの方法があり、処理できないエラー条件を明示的に伝播する必要がないことです。(健全なデフォルトは、コードのどこでもエラーを処理しない場合、事実上、発生しないと断言し、間違っている場合は健全な終了とスタックトレースが残されていることです。)この。Cでエラーを明示的に伝播する必要があるように感じます。
throws FileNotFoundException
。ハードフィックス:catch (FileNotFoundException e) { throw RuntimeException(e); }
チェックされた例外は少し失敗した実験だと言ってもいいと思います。彼らが間違っていたのは、彼らがレイヤーを壊したということです:
AとCに限定されていた可能性のあるエラーの知識をBに分散させる必要があるため、懸念の良い分離は壊れています。
ある素敵な議論ウィキペディア上のチェック例外のは。
Bruce Eckelにも素敵な記事があります。引用です:
[T]プログラマに積み上げるランダムなルール、手近な問題の解決とは関係のないルールは、プログラマが作成できる速度が遅くなります。そして、これは線形因子ではないように見えますが、指数関数的なものです
C ++の場合、すべてのメソッドにthrows
仕様句がある場合、素晴らしい最適化を行うことができます。とにかく、Java RuntimeExceptions
はチェックされていないので、これらの利点があるとは思わない。とにかく、最新のJITはコードを最適に最適化できるはずです。
AspectJの優れた機能の1つは、例外の緩和です。特に、階層化を強化するために、チェック済み例外を未チェック例外に変換できます。
おそらくそれは、Javaは、それがためにチェックしている可能性があり、このトラブルのすべてを行ったことは皮肉だnull
代わりに、はるかに貴重だったかもしれません。
例外が大好きです。
しかし、私は彼らの誤用に絶えず困惑しています。
フロー処理には使用しないでください。例外は作成する必要があるオブジェクトであり、メモリなどを使用する必要があるため、何かを書くためにわざわざできなかったという理由だけで、何かをしようとするコードを望みません。通話を行う前にif()をチェックします。それは怠け者であり、栄光の例外に悪い名前を与えます。
それらを飲み込まないでください。今まで。どんな状況下でも。最低限、ログファイルに何かを貼り付けて、例外が発生したことを示します。例外を飲み込むコードを自分の道で追跡しようとするのは悪夢です。繰り返しになりますが、強大な例外を評判の悪いものにしたことで、例外の飲み込み人をのろいなさい!
OOの帽子をかぶって例外を処理してください。意味のある階層を持つ独自の例外オブジェクトを作成します。ビジネスロジックと例外を連動させて階層化します。以前は、システムの新しい領域で作業を開始した場合、コーディングの30分以内にExceptionをサブクラス化する必要があるため、最近はExceptionクラスを作成することから始めます。
「フレームワーク」コードのビットを書いている場合は、必要に応じて独自の新しい例外をスローするようにすべての初期インターフェースを作成してください... IOExceptionをスローしますが、書き込み先のインターフェイスが 'ReportingApplicationException'をスローしようとしています。
例外を機能させる方法を習得したら、振り返ることはありません。
initCause
て、例外を引き起こした例外とともに使用または初期化します。例:書き込みが失敗した場合にのみ例外が必要なI / Oユーティリティがあります。ただし、書き込みが失敗する可能性がある複数の理由があります(アクセス、書き込みエラーなどを取得できませんでした)元の問題が飲み込まれないように、原因の例外を使用してカスタム例外をスローします。
チェックされた例外もADAにあります。
(警告、この投稿には、あなたが直面するかもしれないと強く信じられている信念が含まれています。)
プログラマーはそれらが好きではなく、文句を言ったり、例外を飲み込むコードを書いたりしません。
チェックされた例外が存在するのは、物事が機能しないだけでなく、障害モード/効果分析を実行して事前に決定できるためです。
ファイルの読み取りが失敗する可能性があります。RPC呼び出しは失敗する可能性があります。ネットワークIOが失敗する可能性があります。解析時にデータが誤ってフォーマットされる可能性があります。
コードの「ハッピーパス」は簡単です。
私は、素晴らしい「ハッピーパス」コードを書くことができる大学の男を知っていました。エッジケースのどれも機能しませんでした。最近、彼はオープンソース企業のPythonをやっています。言っ途切れる。
チェックされた例外を処理したくない場合、あなたが本当に言っているのは
While I'm writing this code, I don't want to consider obvious failure modes.
The User will just have to like the program crashing or doing weird things.
But that's okay with me because
I'm so much more important than the people who will have to use the software
in the real, messy, error-prone world.
After all, I write the code once, you use it all day long.
したがって、チェックされた例外は、より多くの作業を意味するため、プログラマーに好かれることはありません。
もちろん、他の人はその仕事をやりたいと思っているかもしれません。
ファイルサーバーに障害が発生した場合やUSBスティックが故障した場合でも、彼らは正しい答えを望んでいたかもしれません。
あなたの仕事がソフトウェアを書くことであるとき、あなたはあなたの人生をより楽にし、あなたが楽しむプログラミング言語を使うべきであるということは、プログラミングコミュニティにおける奇妙な信念です。あなたの仕事は誰かの問題を解決することであり、プログラムによるジャズの即興演奏に従事させることではありません。
あなたがアマチュアプログラマ(お金のためのプログラミングではない)である場合、C#またはチェックされた例外なしで他の言語で自由にプログラミングしてください。ちなみに、ロゴの中間者とプログラムを切り取ってください。カメを使って床にきれいな模様を描くことができます。
チェックされた例外は、人々がそこに近いエラーを処理することを奨励しているはずです。ソースから離れるほど、実行中に終了する機能が増え、システムが一貫性のない状態に陥る可能性が高くなります。さらに、誤って誤った例外をキャッチする可能性が高くなります。
悲しいことに、人々は例外を無視するか、スロー仕様を増やし続ける傾向がありました。これらは両方とも、チェックされた例外が推奨するものであるという点を見逃しています。それらは、手続き型コードを変換して、おそらくOOにする多くのGetterおよびSetter関数を使用するようなものです。
基本的に、チェック例外は、コードのある程度の正確性を証明しようとしています。コードが実行される前に特定のものが正しいことを証明しようとするという点で、静的型付けとほとんど同じ考えです。問題は、その余分な証拠のすべてが努力を要することであり、その努力は価値があるということですか?