我知道Java异常的开销是在SO上完成的,但是我找不到任何可以解决我情况的事情。我有一个Future,在调用get()时可能会抛出包含任意数量的特定于应用程序的异常的ExecutionException。我想知道使用看起来更漂亮的try-catch块而不是丑陋的if-instanceof-then-cast模式是否存在显着的开销。例如,它可能看起来像这样:
private Response handleException(ExecutionException e) throws MyApplicationException {
try {
throw e.getCause();
} catch (ApplicationException1 e1) {
// known error
throw MyApplicationException.convert(e1);
} catch (ApplicationException2 e2) {
// create error response
return new Response(e2);
} catch (Throwable t) {
// unknown error
throw new RuntimeException(t);
}
}
private Response handleException2(ExecutionException e) throws MyApplicationException {
Throwable cause = e.getCause();
if (cause instanceof ApplicationException1) {
ApplicationException1 e1 = (ApplicationException1) cause;
throw MyApplicationException.convert(e1);
} else if (cause instanceof ApplicationException2) {
ApplicationException2 e2 = (ApplicationException2) cause;
return new Response(e2);
} else {
throw new RuntimeException(cause);
}
}
我的理论是,自
以来不应该有大量的开销答案 0 :(得分:4)
就样式而言,我通常建议不使用异常处理程序进行常规控制流程。我可以在这里看到使用它的论点,因为Future
的设计要求你“解包”原始异常。
重新抛出异常应该比抛出新异常要便宜得多,因为已经填充了堆栈跟踪。您的第一种方法可能仍会有更多的开销,但如果您的应用程序抛出了很多例外情况,影响变得明显,那么您可能会遇到更大的问题。
如果这对你真的很重要,那么你获得有意义答案的唯一方法就是自己衡量差异。但是,同样应该只在例外案件中抛出异常;它们在设计上应该是不常见的。即使您将异常处理的成本加倍,成本也只是 2n 而不是 n 。如果你抛出了很多例外,你的应用程序的性能明显受到影响,那么简单的两个因素可能不会让你失败。因此,请使用您认为更具可读性的风格。
答案 1 :(得分:1)
如果您希望第二个示例看起来更好,则可以在使用原因异常时始终进行转换:
private Response handleException2(ExecutionException e) throws MyApplicationException {
Throwable cause = e.getCause();
if (cause instanceof ApplicationException1) {
throw MyApplicationException.convert((ApplicationException1) cause);
} else if (cause instanceof ApplicationException2) {
return new Response((ApplicationException2) cause);
} else {
throw new RuntimeException(cause);
}
}
答案 2 :(得分:0)
从原始版本更新 写一些简单的代码使HotSpot编译器没有减少到任何东西是相当具有挑战性的,但我认为以下是好的:
package net.redpoint.utils;
public class Scratch {
public long counter = 0;
public class A {
public void inc() { counter++; }
}
public class B extends A {
public void inc() { counter++; }
}
public class C extends A {
public void inc() { counter++; }
}
public A[] a = new A[3];
public void test() {
a[0] = new A();
a[1] = new B();
a[2] = new C();
int iter = 100000000;
long start = System.nanoTime();
for(int i = iter; i > 0; i--) {
testUsingInstanceOf(a[i%3]);
}
long end = System.nanoTime();
System.out.println("instanceof: " + iter / ((end - start) / 1000000000.0) + " per second");
start = System.nanoTime();
for(int i = iter; i > 0; i--) {
testUsingException(a[i%3]);
}
end = System.nanoTime();
System.out.println("try{}: " + iter / ((end - start) / 1000000000.0) + " per second");
start = System.nanoTime();
for(int i = iter; i > 0; i--) {
testUsingClassName(a[i%3]);
}
end = System.nanoTime();
System.out.println("classname: " + iter / ((end - start) / 1000000000.0) + " per second");
}
public static void main(String[] args) {
Scratch s = new Scratch();
s.test();
}
public void testUsingInstanceOf(A possiblyB){
if (possiblyB instanceof B){
((B)possiblyB).inc();
}
}
public void testUsingException(A possiblyB){
try{
((B)possiblyB).inc();
} catch(Exception e){
}
}
public void testUsingClassName(A possiblyB){
if (possiblyB.getClass().getName().equals("net.redpoint.utils.Scratch$B")){
((B)possiblyB).inc();
}
}
}
结果输出:
instanceof: 4.573174070960945E8 per second
try{}: 3.926650051387284E8 per second
classname: 7.689439655530204E7 per second
使用带有Intel i7沙桥CPU的Windows 8 x64上的Oracle JRE7 SE进行测试。