こことかここの話ってこういうことなんかな?
結論としては、ループの回数が多いような処理の中でThrowableで例外返すのはコストが高いのでやめましょう。ってことなのかなと。
そのまま処理をやめるような例外処理ならいいけど、Throwableをcatchしてもそのままループの処理を継続するような場合は、intとかで状態を返す方がよさげな感じ。
科学技術系の計算のような処理でなければ、これを根拠に「Throwable返すのは重いから使用禁止」ってな話にはしたくないって程度じゃないかな?
0除算はなんかは、ArithmeticExceptionをcatchするような処理じゃなくて、予めチェックして処理しましょうってくらいの。
んで、ちょっとintで返す場合とRuntimeExceptionで返す場合を比較してみた。
mode=0は、例外が発生しない。
mode=1は、50%例外が発生する。
mode=2は、100%例外が発生する。
って感じ。
測定すると、
mode | int[ms] | RuntimeException[ms] |
0 | 0 | 0 |
1 | 50 | 850 |
2 | 0 | 1600 |
くらい。
0[ms]の箇所は測定によって、15とか16[ms]になったりするけど、一定というか法則は見たらないので0[ms]としてみた。
mode=2のintが0[ms]な理由がよー判らんけど、まぁ「new RuntimeException()」が遅いってことじゃないかなぁと。
public class ExceptionTest { public ExceptionTest() { super(); } public static void main(String[] args) { ExceptionTest test = new ExceptionTest(); test.test1(0); test.test1(1); test.test1(2); } private void test1(int mode) { long loop = 1000000L; long start1 = System.currentTimeMillis(); int err1 = 0; for ( long i = 0 ; i < loop ; i++ ) { try { if (method1(i, mode) == -1) { err1++; } } catch (RuntimeException e) { err1++; } } long end1 = System.currentTimeMillis(); long start2 = System.currentTimeMillis(); int err2 = 0; for ( long i = 0 ; i < loop ; i++ ) { try { if (method2(i, mode) == -1) { err2++; } } catch (RuntimeException e) { err2++; } } long end2 = System.currentTimeMillis(); System.out.println("[" + mode + "]int " + err1 + "\t" + (end1 - start1)); System.out.println("[" + mode + "]RuntimeException " + err2 + "\t" + (end2 - start2)); } private int method1(long arg, int mode) { if ((mode == 2) || ((mode == 1) && ((arg % 2) == 0))) { return -1; } return 0; } private int method2(long arg, int mode) { if ((mode == 2) || ((mode == 1) && ((arg % 2) == 0))) { throw new RuntimeException(); } return 0; } }
ホントはバイトコードまで見ようかと思ったけど…また今度。
■参考サイト
最適化/例外の使い方
Java 入門 | 例外処理の使い方
How the Java virtual machine handles exceptions - JavaWorld