S_a_k_Uの日記みたいなDB

~サクゥーと呼ばないで~

例外処理のコスト

こことかここの話ってこういうことなんかな?
結論としては、ループの回数が多いような処理の中で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