关于java:抛出并捕获异常,还是使用instanceof?

Throw and catch an exception, or use instanceof?

我在一个变量中有一个异常(没有抛出)。

最好的选择是什么?

1
2
3
4
5
6
7
8
Exception exception = someObj.getExcp();
try {
    throw exception;
} catch (ExceptionExample1 e) {
    e.getSomeCustomViolations();
} catch (ExceptionExample2 e) {
    e.getSomeOtherCustomViolations();
}

1
2
3
4
5
6
Exception exception = someObj.getExcp();
if (exception instanceof ExceptionExample1) {
    exception.getSomeCustomViolations();
} else if (exception instanceof ExceptionExample2) {
    exception.getSomeOtherCustomViolations();
}


我建议使用instanceof,因为它可能更快。抛出异常是一个复杂而昂贵的操作。在不发生异常的情况下,JVM被优化为快速的。例外情况应该是例外。

注意,throw技术可能不会如图所示编译,如果您的异常类型是选中的异常,编译器会抱怨您必须捕获该类型或将其声明为抛出(如果您使用instanceof技术,则对应于else { ... }子句),这可能有帮助,也可能没有帮助,具体取决于您希望如何H处理不是特定子类型之一的异常。


讨厌打破每个人的泡沫,但使用try/catch更快。这并不是说这是"正确"的方式,但如果性能是关键,那么这就是赢家。以下是以下程序的结果:

跑1

  • 子运行1:实例:130 ms
  • 次运行1:尝试/捕获:118 ms
  • 子运行2:实例:96 ms
  • 子运行2:尝试/捕获:93 ms
  • 子运行3:实例:100 ms
  • 子运行3:尝试/捕获:99毫秒

跑2

  • 子运行1:实例:140 ms
  • 子运行1:尝试/捕获:111 ms
  • 子运行2:实例:92 ms
  • 次运行2:尝试/捕获:92 ms
  • 子运行3:实例:105 ms
  • 次运行3:尝试/捕获:95毫秒

跑3

  • 子运行1:实例:140 ms
  • 子运行1:尝试/捕获:135 ms
  • 子运行2:实例:107 ms
  • 子运行2:尝试/捕获:88毫秒
  • 子运行3:实例:96 ms
  • 次运行3:尝试/捕获:90 ms

测试环境

  • Java:1.7.0Y45
  • 麦克奥斯克斯小牛队

每一个运行的预热子运行的折扣,instanceof方法只能达到最好的try/catch的性能。instanceof方法的平均(折现热身)为98ms,try/catch方法的平均值为92ms。

请注意,我没有改变每种方法的测试顺序。我总是先测试一块instanceof,然后测试一块try/catch。我希望看到其他结果与这些发现相矛盾或证实。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public class test {

    public static void main (String [] args) throws Exception {
        long start = 0L;
        int who_cares = 0; // Used to prevent compiler optimization
        int tests = 100000;

        for ( int i = 0; i < 3; ++i ) {
            System.out.println("Testing instanceof");
            start = System.currentTimeMillis();
            testInstanceOf(who_cares, tests);
            System.out.println("instanceof completed in"+(System.currentTimeMillis()-start)+" ms"+who_cares);

            System.out.println("Testing try/catch");
            start = System.currentTimeMillis();
            testTryCatch(who_cares, tests);
            System.out.println("try/catch completed in"+(System.currentTimeMillis()-start)+" ms"+who_cares);
        }
    }

    private static int testInstanceOf(int who_cares, int tests) {
        for ( int i = 0; i < tests; ++i ) {
            Exception ex = (new Tester()).getException();
            if ( ex instanceof Ex1 ) {
                who_cares = 1;
            } else if ( ex instanceof Ex2 ) {
                who_cares = 2;
            }
        }
        return who_cares;
    }

    private static int testTryCatch(int who_cares, int tests) {
        for ( int i = 0; i < tests; ++i ) {
            Exception ex = (new Tester()).getException();
            try {
                throw ex;
            } catch ( Ex1 ex1 ) {
                who_cares = 1;
            } catch ( Ex2 ex2 ) {
                who_cares = 2;
            } catch ( Exception e ) {}
        }
        return who_cares;
    }

    private static class Ex1 extends Exception {}

    private static class Ex2 extends Exception {}

    private static java.util.Random rand = new java.util.Random();

    private static class Tester {
        private Exception ex;
        public Tester() {
            if ( rand.nextBoolean() ) {
                ex = new Ex1();
            } else {
                ex = new Ex2();
            }
        }
        public Exception getException() {
            return ex;
        }
    }
}


我强烈建议您实际使用一个简单的对象来表示您的"约束"。标记接口(如Messagejava.lang.String由您决定。异常并不意味着按照您的意愿来使用,即使其中任何一个都可以工作(我希望第二个更快,但这是一个过早的优化…)。


还可以通过为包含getCustomViolation()方法的自定义异常创建接口来使用多态性。然后,每个自定义异常都将实现该接口和该方法。