执行一个catch代码块和抛出一个异常花费是很高的,这个过程中的性能损耗主要是由于当创建一个异常时要获得线程栈的一个快照。抛出异常首先要创建一个新的对象Throwable类的构造函数调用名为fillInStackTrace的方法,fillInStackTrace方法检查堆栈,收集调用跟踪信息。由于在处理过程中创建了一个新的对象,所以说只要有异常被抛出,JVM就必须调整调用堆栈,系统资源开销也就增大了。
1、使编译器和运行时最优化,将几个方法调用放在一个try/catch块中,而不是为每个方法调用各自使用try/catch块
try{
Some.method1();
}catch(method1Exception e){
handle exception 1
}
try{
Some.method2();
}catch(method2Exception e){
handle exception 2
}
try{
Some.method3();
}catch(method3Exception e){
handle exception 3
}
应当优化为如下代码
try{
Some.method1();
Some.method2();
Some.method3();
}catch(method1Exception e){
handle exception 1
}catch(method2Exception e){
handle exception 2
}catch(method3Exception e){
handle exception 3
}
2、异常只能用于错误处理,不应该用来控制程序流程。
public class Test {
int value;
public int getValue() {
return value;
}
public void reset() {
value = 0;
}
// Calculates without exception
public void method1(int i) {
value = ((value + i) / i) << 1;
// Will never be true
if ((i & 0xFFFFFFF) == 1000000000) {
System.out.println("You'll never see this!");
}
}
// Could in theory throw one, but never will
public void method2(int i) throws Exception {
value = ((value + i) / i) << 1;
// Will never be true
if ((i & 0xFFFFFFF) == 1000000000) {
throw new Exception();
}
}
// This one will regularly throw one
public void method3(int i) throws Exception {
value = ((value + i) / i) << 1;
// i & 1 is equally fast to calculate as i & 0xFFFFFFF; it is both
// an AND operation between two integers. The size of the number plays
// no role. AND on 32 BIT always ANDs all 32 bits
if ((i & 0x1) == 1) {
throw new Exception();
}
}
public static void main(String[] args) {
int i;
long l;
Test t = new Test();
l = System.currentTimeMillis();
t.reset();
for (i = 1; i < 100000000; i++) {
t.method1(i);
}
l = System.currentTimeMillis() - l;
System.out.println(
"method1 took " + l + " ms, result was " + t.getValue()
);
l = System.currentTimeMillis();
t.reset();
for (i = 1; i < 100000000; i++) {
try {
t.method2(i);
} catch (Exception e) {
System.out.println("You'll never see this!");
}
}
l = System.currentTimeMillis() - l;
System.out.println(
"method2 took " + l + " ms, result was " + t.getValue()
);
l = System.currentTimeMillis();
t.reset();
for (i = 1; i < 100000000; i++) {
try {
t.method3(i);
} catch (Exception e) {
// Do nothing here, as we will get here
}
}
l = System.currentTimeMillis() - l;
System.out.println(
"method3 took " + l + " ms, result was " + t.getValue()
);
}
}
上段代码首先创建了三个方法,在这三个方法当中第一个没有抛出异常,第二个当符合条件的时候抛出异常,第三个和第二个一样。(实际上三个方法中value的存在就是为了延长程序的运行时间,没有实际意义。)从运行结果可以看出来抛出异常是相当消耗资源的,尽管有时不出现异常时性能尚可,但是依然不建议用异常控制程序流程。
不做多余的的事情就是调优,保证功能实现的情况下最低程度的减少开销就是优化。