42

Java の try-catch メカニズムを使用するとオーバーヘッドが発生すると言われました。そのため、可能性のある例外を処理するには、チェック済み例外をスローするメソッドを try ブロック内に配置する必要がありますが、try ブロックのサイズを制限して、例外をスローする可能性のある操作のみを含めることをお勧めします。

これが賢明な結論かどうかはわかりません。

指定されたテキスト ファイルを処理する関数の以下の 2 つの実装を検討してください。

最初の方法で不必要なオーバーヘッドが発生することは事実ですが、私はそれを理解するのがはるかに簡単だと思います. ステートメントを見るだけでは、例外がどこから来るのか正確にはわかりませんが、コメントはどのステートメントが原因であるかを明確に示しています。

2 番目のものは、最初のものよりもはるかに長く、複雑です。特に、最初の優れた行読みイディオムは、readLine呼び出しを try ブロックに収めるためにマングルする必要があります。

定義で複数の例外がスローされる可能性がある関数で例外を処理するためのベスト プラクティスは何ですか?

これには、try ブロック内のすべての処理コードが含まれています。

void processFile(File f)
{
  try
  {
    // construction of FileReader can throw FileNotFoundException
    BufferedReader in = new BufferedReader(new FileReader(f));

    // call of readLine can throw IOException
    String line;
    while ((line = in.readLine()) != null)
    {
      process(line);
    }
  }
  catch (FileNotFoundException ex)
  {
    handle(ex);
  }
  catch (IOException ex)
  {
    handle(ex);
  }
}

これには、try ブロック内で例外をスローするメソッドのみが含まれています。

void processFile(File f)
{
  FileReader reader;
  try
  {
    reader = new FileReader(f);
  }
  catch (FileNotFoundException ex)
  {
    handle(ex);
    return;
  }

  BufferedReader in = new BufferedReader(reader);

  String line;
  while (true)
  {
    try
    {
      line = in.readLine();
    }
    catch (IOException ex)
    {
      handle(ex);
      break;
    }

    if (line == null)
    {
      break;
    }

    process(line);
  }
}
4

7 に答える 7

49

ここでの基本的な前提は誤りですtry。ブロックのサイズはパフォーマンスに違いはありません。パフォーマンスは、実行時に実際に例外を発生させることによって影響を受けます。これは、tryブロックのサイズとは無関係です。

ただし、try ブロックを小さくしておくと、より良いプログラムにつながる可能性があります。

回復して続行するために例外をキャッチする場合もあれば、呼び出し元 (または何らかの UI を介して人間に) に報告するためだけに例外をキャッチする場合もあります。

最初のケースでは、回復可能な障害は非常に限定的であることが多く、これによりtryブロックが小さくなります。

2 番目のケースでは、別の例外によってラップされて再スローされるか、ユーザーに表示されるように例外がキャッチされます。小さなtryブロックは、どの操作が失敗したかをより正確に知ることを意味し、より高いレベルのコンテキストで失敗したことを意味します。その呼び出しが行われました。これにより、より具体的なエラー レポートを作成できます。

もちろん、これらのガイドラインには… 例外があります (申し訳ありません!)。たとえば、場合によっては、非常に具体的なエラー レポートがセキュリティ上の問題になる可能性があります。


tryブロックがコンパイルされたコードにどのような影響を与えるかを知っておくと役立つ場合があります。コンパイルされた命令はまったく変更されません! (もちろん、catch他のコードと同様なので、対応するブロックも同様です。)

tryブロックは、メソッドに関連付けられた例外テーブルにエントリを作成します。このテーブルには、さまざまなソース命令カウンター、例外タイプ、および宛先命令が含まれています。例外が発生すると、このテーブルを調べて、タイプが一致するエントリと、例外を発生させた命令を含む範囲があるかどうかを確認します。存在する場合、実行は対応する宛先番号に分岐します。

重要なことは、このテーブルは必要でない限り参照されない (実行中のパフォーマンスには影響しない) ということです。(クラスのロード時のオーバーヘッドを少し無視しています。)

于 2010-04-13T23:44:04.180 に答える
12

Javaのtry-catchメカニズムを使用するとオーバーヘッドが発生すると言われています。

絶対。また、メソッド呼び出しにもオーバーヘッドがあります。ただし、すべてのコードを1つのメソッドにまとめるべきではありません。

時期尚早の最適化ホーンを宣伝するのではなく、読みやすさ、構成などに焦点を当てる必要があります。言語構成が、システム構成やアルゴリズムの選択ほどパフォーマンスに影響を与えることはめったにありません。

私にとって、最初のものが最も読みやすいです。

于 2010-04-13T23:27:40.303 に答える
3

いいえ。考慮すべき唯一のことは、例外を合理的に処理できる場所と、(finally を使用して) 再利用する必要があるリソースです。

于 2010-04-13T23:58:37.863 に答える
2

これは、最悪の場合、時期尚早の最適化です。やらないでください。

「私たちは小さな効率を忘れるべきです。たとえば、約 97% の確率で: 時期尚早の最適化はすべての悪の根源です」 - Knuth.

于 2010-04-14T03:01:35.530 に答える
1

2番目の方法にはほとんどメリットがありません。結局のところ、ファイルを正常に開くことができても、ファイルから読み取ることができない場合は、コンピューターに非常に問題があります。したがって、io例外がreadLine()メソッドから発生したことを知っていることは、ほとんど役に立ちません。また、ご存知のように、とにかくさまざまな問題に対してさまざまな例外がスローされます(FileNotFoundExceptionなど)

'論理'ブロックでスコープを設定する限り、つまり、ファイルを1回で開いたり、読み取ったり、閉じたりする限り、最初の方法を使用します。読み取りがはるかに簡単で、特にIOを処理する場合、try-catchオーバーヘッドによって使用されるプロセッササイクルは、あるとしても最小限に抑えられます。

于 2010-04-13T23:20:47.853 に答える
1

例外をスローする可能性のある特定のコードの周りにtryブロックを配置すると、私の意見では読みやすくなります。エラーごとに異なるメッセージを表示し、ユーザーに指示を提供することをお勧めします。これは、エラーが発生する場所によって異なります。

ただし、ほとんどの人が言及するパフォーマンスの問題は、tryブロック自体ではなく、例外の発生に関連しています。

つまり、エラーが発生しない限り、tryブロックがパフォーマンスに目立った影響を与えることはありません。tryブロックを別のフロー制御構造と見なして、コードを分岐するためのエラーを発生させるべきではありません。それはあなたが避けたいものです。

于 2010-04-13T23:29:34.430 に答える
0

2番目のメソッドは、初期化されていない可能性のあるコンパイラエラーを生成しreaderます。に初期化することでそれを回避できますがnull、それは単にNPEを取得できることを意味し、それには利点がありません。

于 2010-04-13T23:23:18.043 に答える