Javaの例外処理はかなり高価だといつも言われていました。
私はそれがプログラムの始めにそしていつも同じ例外オブジェクトを投げて、新しいものを作成せずに特定の型の例外インスタンスを作成することが良い習慣であるかどうか尋ねています。
例を挙げたいだけです。共通コード
if (!checkSomething(myObject))
throw new CustomException("your object is invalid");
代替案
static CustomException MYEXP = new CustomException("your object is invalid");
//somewhere else
if (!checkSomething(myObject))
throw MYEXP;
もちろん、ここではいくつかの仮定をしています。
MyCustomException
パラメータはありません質問は以下のとおりです。
私はこれが愚かな質問ではないことを願っています、私はこれについて興味があります。例外処理にかかる実際のコストは取り扱いそして創造ではありません。
編集するFOSDEMプレゼンテーションに関する正確な議論の参照を追加しました
免責事項:私のコードはどれも提案されたようには動作せず、私はこのような例外を管理するつもりはありません。私はただ「what-if」の質問をしています。私が考えたのは、もしそれがScalaで行われるのなら、なぜJavaではないのでしょうか。
いいえ、しないでください。高価な部分は例外を処理していない、それはスタックトレースを生成しています。残念ながら、スタックトレースも便利な部分です。もしあなたが保存された例外を投げるなら、あなたは誤解を招くスタックトレースを渡すでしょう。
Scalaの実装内でこれを行うのが理にかなっている状況があるかもしれません。 (たぶん彼らは再帰的なことをしていて、例外オブジェクトを前もって生成したいのでそれらがメモリを使い果たした場合でも例外を生成することができます。)彼らはまた彼らがしていることについて多くの情報を持っています。それを正しくすることのしかし、JVM言語の実装者による最適化は非常に特殊なケースです。
だからあなたはそうではないでしょう壊れる誤解を招くような情報を提供することは、破損を招くと思わない限り、何でも。それは私にとって大きなリスクのようです。
スタックトレースなしで例外を作成する方法に関するThomas Edingの提案を試してもうまくいくようです。
groovy:000> class MyException extends Exception {
groovy:001> public Throwable fillInStackTrace() {}}
===> true
groovy:000> e = new MyException()
===> MyException
groovy:000> Arrays.asList(e.stackTrace)
===> []
またチェックアウトJLS:
NullPointerException(一種のRuntimeException)です。 メソッドblowUpによってスローされるのは、mainの中のtry文では捕捉されません。 NullPointerExceptionは型の変数に代入できないため それを吹きました。これによりfinally節が実行され、その後に テストプログラムの唯一のスレッドであるmainを実行するスレッド キャッチされていない例外のために終了します。 例外名と単純なバックトレースを表示することに。しかし、 この仕様ではバックトレースは必要ありません。
バックトレースを強制することの問題は、例外が プログラムのある時点で作成され、後の時点でスローされます。それは 例外がない限り例外でスタックトレースを格納するのは法外に高価です。 実際にスローされます(その場合、トレースは スタックを巻き戻します。それ故に私達はすべてでバックトレースを強制しません 例外。
Q1。これは良い習慣ですか?
私の本にはありません。それは複雑さを増し、診断を妨げます(Q2への私の答えを見てください)。
Q2。これは何らかのJVMメカニズムにダメージを与えますか?
そのような例外オブジェクトからは意味のあるスタックトレースが得られません。
Q3。 1がイエスならば、パフォーマンスの向上はありますか? (私はそうは思いませんが、よくわかりません)
Q4。 1と3がイエスなら、なぜ実践として後援されないのですか?
上記の問題が原因で。
Q5。 1が「いいえ」の場合、Martin OderskyがScalaの紹介で、これがScalaの動作のしくみであると説明した理由は何ですか? (申し訳ありませんが、現時点ではこの肯定の文脈を思い出すことができません)Fosdem 2009
文脈なしで答えるのは難しい。
あなたはそれを行うことができますが、例外
最初のスタックトレースは、その後の使用で混乱を招くだけなので、スタックトレースを含んではいけません。
抑制された例外を受け入れてはいけません。複数のスレッドが抑制された例外をそれに追加しようとすると、物事は壊れるでしょう。
だからあなたの例外コンストラクタはしなければならない
super(msg, cause, /*enableSuppression*/false, /*writableStackTrace*/false);
今、それは便利ですか?そうです、そうでなければ、なぜこれら2つのブール値フラグがそもそも存在するのでしょうか?:)
複雑な場合には、例外をフロー制御装置として使用することができます。それはより単純でより速いコードを生成するかもしれません。そのような例外は「制御例外」として知られています。
例外が本当にプログラムに例外的に悪い何かを示すことであるなら、それから伝統的な例外を使いなさい。
例外は比較的高価で最小限に抑える必要がありますが、「パフォーマンス上の理由から」鈍いことをする必要があるほど高価ではありません。絶対に避けてください。それは完全には真実ではありませんが、あなたは例外がどれくらい遅いかを測定することができます。
long start = System.nanoTime();
int exceptionCount = 0;
for (int i = 0; i < 20000; i++)
try {
int j = i / (i & 1);
} catch (ArithmeticException ae) {
exceptionCount++;
}
long time = System.nanoTime() - start;
System.out.printf("Each exception took average of %,d ns%n", time / exceptionCount);
合理的な見積もりであると私が思うものを印刷します。
Each exception took average of 3,064 ns
注:ループ数が増えるにつれて、例外は最適化されます。すなわち10倍の繰り返し
Each exception took average of 327 ns
そして10倍以上
Each exception took average of 35 ns
そして10倍以上
Each exception took average of 5 ns
例外が十分にスローされれば、JITは例外を最適化するのに十分スマートであるように見えます。
if
これは必要であるthen
何かelse
間違っている。 - NominSim