2013-06-17 9 views
5

私はちょっとした問題を抱えていますが、try catch節を使って作業するときは、取得できる正確な例外を指定する方が良いでしょうか、例外を使用するほうが良いのですか? 例:例外を指定するかどうかを指定します。

try { 
    whatever 
} catch (NullPointerException ex) { 
    whatever 
} 

かは気にしない場合は、例外の種類:

try { 
    whatever 
} catch (Exception ex) { 
    whatever 
} 

私はあなたが異なる効果をトリガするために別の例外を使用することができることを知っているので、私はちょうどのために求めていますパフォーマンス。

+0

「Throwable」をキャッチする場合を除いて、パフォーマンスが同じであることは、プログラムが「Throwable」の型をチェックする必要があるより具体的なものです。しかし、これは単なる推測です。 – asteri

+0

あなた自身でベンチマークを行い、ここに結果を投稿してみませんか? – anubhava

+5

@anubhava何かをベンチマークしようとするたびに、私はベンチマークが適切ではないと言われます。母: – asteri

答えて

0

パフォーマンスが例外捕捉に関して何らかの形で関係している場合は、例外ではありません。

私がしていることはすべてテストなので、それが本当の違いになるのではないかと疑います。

キャッチ例外はとにかく稀です。

あなたは

try 
{ 
    whatever 
} 
catch (MyException10 ex10) 
{ 
    whatever 
} 
catch (MyException9 ex9) 
{ 
    whatever 
} 
... 
catch (MyException1 ex1) 
{ 
    whatever 
} 

をしていたなら、あなたは潜在的なパフォーマンスの改善を主張することができ、それはとても1つのビットは、非常に多くの例外をスローしませんでしたあなたのコードを手直しだろう...

+1

私はOPが一般的な例外捕捉プロセスにもっと興味があり、Javaが 'MoreSpecificException'を捕まえるのとは違って' Exception'捕捉を扱うのであれば、 – arshajii

+0

多くの例外を投げることを避けることが不可能なAPIを使用している場合があります。たとえば、項目が存在しない場合にはスローするが、項目が存在するかどうかをテストする他の手段は含まれない「項目の取得」メソッドを含むディクショナリのishインターフェースを持つことができます。そのようなインタフェースがうまく設計されていないことが、必ずしもそれを変更することを可能にするとは限らない。そのような場合は、例外処理のパフォーマンスが非常に重要になる場合があります。 – supercat

+0

それは継承ツリーの1つの地獄であり、あなたは多くの例外をスローする必要があります。いずれにしても例外ではありません。 supercatで述べたようにAPIで詰め込まれている場合は、もっと効率的に処理しようとするのを邪魔しない方法を探しています。テストのコストは、実際の例外自体に比べて些細なものです。 –

0

最高のパフォーマンス私が思いつくことができるtry/catchブロックのアドバイスは、それらを小さくすることです。

あなたは、言って、3つの例外を投げることができるコードの一部を持っている場合:

try { 
    piece1(); 
} catch (Exception1 e) { 
    // whatever 
} 

try { 
    piece2(); 
} catch (Exception2 e) { 
    // whatever 
} 

try { 
    piece3(); 
} catch (Exception3 e) { 
    // whatever 
} 

この方法は、することができますreturn/break/continue早いです。そして、それぞれの例外を扱うように扱います。まれに何が摘発されたかは気にしません。

ブロックが広すぎると、予想外の例外がスローされる可能性があります。特に、Exceptionを捕まえると(NullPointerExceptionArrayIndexOutOfBoundsExceptionなどの細かい点を含む)、すべてRuntimeExceptionがキャッチされます。そして、これは良い(tm)ではありません。

2

ここでの正しい答えは、パフォーマンスとは対照的にプログラム上の理由により適切な例外処理を使用することです。 (パフォーマンスを無視する)場合は、NullPointerExceptionをキャッチする方が適切でしょう。

例外は例外的なケースです。まれに、例外処理のパフォーマンスが正しさよりも重要ではないはずです。

アプリケーションがこのような状況を定期的に予測している場合は、例外以外のメカニズムを使用して処理する必要があります。例外をスローするのは常に高価なため、パフォーマンスが心配な場合は特にそうです。

4

私のテストによると、はパフォーマンスに大きな違いがありませんです。

各実行では、各シナリオで1,000万回の試行が行われ、実行時間がナノ秒単位と同様に丸められた秒単位で比較されます。これは実際に私の元の仮説に反しています。私はThrowableを捕まえれば、目に見える改善が見られると考えていました。

また、この部分がオプティマイザの影響を受けている可能性があることもわかり始めたので、オプティマイザが持つ潜在的な影響を緩和するため、疑似乱数を含む複雑な例を作成しました。コード上に

(質問は具体的には約パフォーマンス、ではないのベストプラクティスであると私は、catchブロックの適切な使用についてご講義はありません。)この点以下のデータの

たくさん!

ラン1の結果:

Exception: 7196141955 (7.196s) 
NumberFormatException: 7736401837 (7.736s) 
Throwable: 6818656505 (6.819s) 

ラン2件の結果:

Exception: 7262897545 (7.263s) 
NumberFormatException: 7056116050 (7.056s) 
Throwable: 7108232206 (7.108s) 

実験3件の結果:

Exception: 7088967045 (7.089s) 
NumberFormatException: 7020495455 (7.020s) 
Throwable: 7192925684 (7.193s) 

実験4件の結果:

Exception: 6916917328 (6.917s) 
NumberFormatException: 7690084994 (7.690s) 
Throwable: 6906011513 (6.906s) 

ラン5件の結果:

Exception: 7247571874 (7.248s) 
NumberFormatException: 6818511040 (6.819s) 
Throwable: 6813286603 (6.813s) 

コード

import java.math.BigDecimal; 
import java.math.RoundingMode; 

public class Test { 

    private static final int TRIALS = 10000000; 
    private static final int NANOS_IN_SECOND = 1000000000; 
    private static final int DECIMAL_PRECISION = 3; 
    private static final RoundingMode ROUNDING_MODE = RoundingMode.HALF_UP; 

    public static void main(String[] args) { 

     long firstStart = System.nanoTime(); 

     for(int i = 0; i < TRIALS; i++) { 
      try { 
       throw new NumberFormatException(); 
      } 
      catch(Exception e) { 

      } 
     } 

     long firstEnd = System.nanoTime(); 

     long secondStart = System.nanoTime(); 

     for(int i = 0; i < TRIALS; i++) { 
      try { 
       throw new NumberFormatException(); 
      } 
      catch(NumberFormatException e) { 

      } 
     } 

     long secondEnd = System.nanoTime(); 

     long thirdStart = System.nanoTime(); 

     for(int i = 0; i < TRIALS; i++) { 
      try { 
       throw new NumberFormatException(); 
      } 
      catch(Throwable e) { 

      } 
     } 

     long thirdEnd = System.nanoTime(); 

     long exception = firstEnd - firstStart; 
     long numberFormatException = secondEnd - secondStart; 
     long throwable = thirdEnd - thirdStart; 

     BigDecimal exceptionSeconds = new BigDecimal((double)exception/(double)NANOS_IN_SECOND); 
     BigDecimal numberFormatExceptionSeconds = new BigDecimal((double)numberFormatException/(double)NANOS_IN_SECOND); 
     BigDecimal throwableSeconds = new BigDecimal((double)throwable/(double)NANOS_IN_SECOND); 

     exceptionSeconds = exceptionSeconds.setScale(DECIMAL_PRECISION, ROUNDING_MODE); 
     numberFormatExceptionSeconds = numberFormatExceptionSeconds.setScale(DECIMAL_PRECISION, ROUNDING_MODE); 
     throwableSeconds = throwableSeconds.setScale(DECIMAL_PRECISION, ROUNDING_MODE); 

     System.out.println("Exception: " + exception + " (" + exceptionSeconds + "s)"); 
     System.out.println("NumberFormatException: " + numberFormatException + " (" + numberFormatExceptionSeconds + "s)"); 
     System.out.println("Throwable: " + throwable + " (" + throwableSeconds + "s)"); 

    } 

} 

より回旋、擬似ランダムコード

コードブロックが常にcatchに流れることを認識して、オプティマイザがスロー/キャッチプロセス全体を単に「無視する」のではないことを確認するために、これを作成しました。無作為に選択されたString(しかし常に無効なもの)上でInteger.parseInt()を試行することによって、コンパイラは実行時までfor()ループを介した実行が有効かどうかを知ることができません。

第1の実験から予想されるように、3つのシナリオの間には大きな違いはありません。

ラン1の結果:

Exception: 10988431371 (10.988s) 
NumberFormatException: 11360698958 (11.361s) 
Throwable: 10539041505 (10.539s) 

ラン2件の結果:

Exception: 12468860076 (12.469s) 
NumberFormatException: 11852429194 (11.852s) 
Throwable: 11859547560 (11.860s) 

実験3件の結果:

Exception: 10618082779 (10.618s) 
NumberFormatException: 10718252324 (10.718s) 
Throwable: 10327709072 (10.328s) 

実験4の結果:

Exception: 11031135405 (11.031s) 
NumberFormatException: 10689877480 (10.690s) 
Throwable: 10668345685 (10.668s) 

ラン5つの結果:この場合

Exception: 11513727192 (11.514s) 
NumberFormatException: 11581826079 (11.582s) 
Throwable: 12488301109 (12.488s) 

コード

import java.math.BigDecimal; 
import java.math.RoundingMode; 
import java.util.Random; 

public class Test { 

    private static final int TRIALS = 10000000; 
    private static final int NANOS_IN_SECOND = 1000000000; 
    private static final int DECIMAL_PRECISION = 3; 
    private static final RoundingMode ROUNDING_MODE = RoundingMode.HALF_UP; 

    private static final String[] TEST_STRINGS = { 
     "lawl", 
     "rofl", 
     "trololo", 
     "foo", 
     "bar" 
    }; 

    private static final Random RANDOM = new Random(); 



    public static void main(String[] args) { 

     long firstStart = System.nanoTime(); 

     for(int i = 0; i < TRIALS; i++) { 
      try { 
       Integer.parseInt(TEST_STRINGS[RANDOM.nextInt(TEST_STRINGS.length)]); 
      } 
      catch(Exception e) { 

      } 
     } 

     long firstEnd = System.nanoTime(); 

     long secondStart = System.nanoTime(); 

     for(int i = 0; i < TRIALS; i++) { 
      try { 
       Integer.parseInt(TEST_STRINGS[RANDOM.nextInt(TEST_STRINGS.length)]); 
      } 
      catch(NumberFormatException e) { 

      } 
     } 

     long secondEnd = System.nanoTime(); 

     long thirdStart = System.nanoTime(); 

     for(int i = 0; i < TRIALS; i++) { 
      try { 
       Integer.parseInt(TEST_STRINGS[RANDOM.nextInt(TEST_STRINGS.length)]); 
      } 
      catch(Throwable e) { 

      } 
     } 

     long thirdEnd = System.nanoTime(); 

     long exception = firstEnd - firstStart; 
     long numberFormatException = secondEnd - secondStart; 
     long throwable = thirdEnd - thirdStart; 

     BigDecimal exceptionSeconds = new BigDecimal((double)exception/(double)NANOS_IN_SECOND); 
     BigDecimal numberFormatExceptionSeconds = new BigDecimal((double)numberFormatException/(double)NANOS_IN_SECOND); 
     BigDecimal throwableSeconds = new BigDecimal((double)throwable/(double)NANOS_IN_SECOND); 

     exceptionSeconds = exceptionSeconds.setScale(DECIMAL_PRECISION, ROUNDING_MODE); 
     numberFormatExceptionSeconds = numberFormatExceptionSeconds.setScale(DECIMAL_PRECISION, ROUNDING_MODE); 
     throwableSeconds = throwableSeconds.setScale(DECIMAL_PRECISION, ROUNDING_MODE); 

     System.out.println("Exception: " + exception + " (" + exceptionSeconds + "s)"); 
     System.out.println("NumberFormatException: " + numberFormatException + " (" + numberFormatExceptionSeconds + "s)"); 
     System.out.println("Throwable: " + throwable + " (" + throwableSeconds + "s)"); 

    } 

} 
+0

+1このベンチマークを書く努力のために、私はそれが適切なベンチマーキングであると信じています:P – anubhava

+0

そのすべてのテストに感謝します。 –

1

、どちらも。 try/catchは比較的高価で、控えめに使用する必要があります。 NullPointerExceptionをキャッチするよりも、ヌルを手動でチェックする方がよいでしょう。

関連する問題