13

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;

もちろん、ここではいくつかの仮定を行っています。

  1. MyCustomExceptionパラメータがありません
  2. クライアントコードは、良い習慣であるかどうかにかかわらず、例外処理に大きく基づいており、リファクタリングはオプションではありません.

質問は次のとおりです。

  1. これは良い習慣ですか?
  2. これは一部の JVM メカニズムに損傷を与えますか?
  3. 1 が「はい」の場合、パフォーマンスが向上する可能性はありますか? (ないと思いますが、よくわかりません)
  4. 1 と 3 が「はい」の場合、なぜ実践として後援されないのですか?
  5. 1 が「いいえ」の場合、Martin Odersky が Scala の紹介で、場合によっては Scala がどのように機能するかを説明したのはなぜですか? (28:30 で、ブレークが実装されていると例外がスローされたと彼は言いました。聴衆はこれには時間がかかると言い、彼は毎回例外が作成されるわけではないと答えました) Fosdem 2009

これが怠惰/愚かな質問ではないことを願っています。私はこれに興味があります。例外処理の真のコストは作成ではなく処理だと思います。

編集 FOSDEM プレゼンテーションに関する正確な議論の参照を追加

免責事項: 私のコードはどれも提案どおりに機能せず、このような例外を管理するつもりはありません。「もしも」の質問をしているだけで、この好奇心はビデオの肯定から生成されます。私は考えました: もしそれが Scala で行われているのなら、なぜ Java ではないのでしょうか?

4

4 に答える 4

18

いいえ、そうしないでください。高価な部分は例外を処理せず、スタックトレースを生成しています。残念ながら、スタックトレースも便利な部分です。保存された例外をスローすると、誤解を招くスタックトレースが渡されます。

Scalaの実装内で、これを行うことが理にかなっている状況がある可能性があります。(おそらく、再帰的に何かを実行していて、事前に例外オブジェクトを生成したいので、メモリが不足した場合でも例外を生成できます。)また、実行していることに関する多くの情報を持っているため、より良いチャンスがあります。それを正しくすることの。ただし、JVM言語の実装者による最適化は非常に特殊なケースです。

したがって、誤解を招く情報を提供することが破損であると思わない限り、何も破損することはありません。それは私にとって大きなリスクのようです。

スタックトレースなしで例外を作成する方法についてのThomasEdingの提案を試してみると、うまくいくようです。

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もチェックしてください:

メソッドblowUpによってスローされるNullPointerException(RuntimeExceptionの一種)は、NullPointerExceptionがBlewItタイプの変数に割り当てられないため、mainのtryステートメントによってキャッチされません。これによりfinally句が実行され、その後、テストプログラムの唯一のスレッドであるmainを実行しているスレッドが、キャッチされない例外のために終了します。これにより、通常、例外名と単純なバックトレースが出力されます。ただし、この仕様ではバックトレースは必要ありません。

バックトレースを義務付けることの問題は、プログラムのある時点で例外が作成され、後で例外がスローされる可能性があることです。実際にスローされない限り、例外にスタックトレースを格納することは非常にコストがかかります(この場合、スタックの巻き戻し中にトレースが生成される可能性があります)。したがって、すべての例外でバックトレースを義務付けるわけではありません。

于 2013-01-23T21:28:45.240 に答える
3

Q1. これは良い習慣ですか?

私の本にはありません。複雑さが増し、診断が妨げられます (Q2 に対する私の回答を参照してください)。

Q2. これは一部の JVM メカニズムに損傷を与えますか?

このような例外オブジェクトから意味のあるスタック トレースを取得することはできません。

Q3. 1 が「はい」の場合、パフォーマンスの向上はありますか? (ないと思いますが、よくわかりません)

Q4. 1 と 3 が「はい」の場合、なぜ実践として後援されないのですか?

上記の問題が原因です。

Q5. 1 が「いいえ」の場合、Martin Odersky が Scala の紹介で、場合によっては Scala がどのように機能するかを説明したのはなぜですか? (申し訳ありませんが、現時点ではこの肯定の文脈を思い出せません) Fosdem 2009

文脈がないと答えにくい。

于 2013-01-23T21:30:38.557 に答える
3

あなたはそれを行うことができますが、例外

  1. 最初のスタックトレースはその後の使用で混乱を招くだけなので、スタックトレースはありません。

  2. 抑制された例外を受け入れてはなりません。複数のスレッドが抑制された例外を追加しようとすると、問題が発生します。

したがって、例外コンストラクターは行う必要があります

super(msg, cause, /*enableSuppression*/false, /*writableStackTrace*/false);

http://docs.oracle.com/javase/7/docs/api/java/lang/Throwable.html#Throwable%28java.lang.String,%20java.lang.Throwable,%20boolean,%20boolean%29を参照してください。


さて、それは役に立ちますか?そうでなければ、そもそもなぜこれら 2 つのブール値フラグが存在するのでしょうか?:)

一部の複雑なケースでは、例外をフロー制御デバイスとして使用できます。これにより、より単純で高速なコードが生成される場合があります。このような例外は「制御例外」として知られています。

例外が実際にプログラムの例外的な問題を示す場合は、従来の例外を使用してください。

于 2013-01-23T23:10:27.760 に答える
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 は Exception を最適化するのに十分スマートであるように見えます。

于 2013-01-23T21:59:15.353 に答える