您的位置:首页 > 其它

try-catch-finally的使用

2015-08-03 12:03 417 查看
try-catch-finally语句与return联合使用、try-catch对程序性能的影响。我做了九个对比小实验进行研究,得到以下结论:

**1、finally语句在return语句执行之后return返回之前执行的。

2、finally块中的return语句会覆盖try块中的return返回。

3、如果finally语句中没有return语句覆盖返回值,那么原来的返回值可能因为finally里的修改而改变也可能不变。如果返回基本数据类型不会受finally中的修改影响,如果是返回引用类型会受finally中的修改影响。

4、try块里的return语句在异常的情况下不会被执行,这样具体返回哪个看情况。

5、当发生异常后,catch中的return执行情况与未发生异常时try中return的执行情况完全一样。

6、无异常时候,try-catch几乎不影响程序运行时间。

7、有异常的时候,异常类型匹配越精确越少时间开销。

8、不单纯的用Exception过滤异常、尽量少地在try里面添加代码、尽量不在循环里使用try-catch**

实验只是对try-catch-finally的初步认识,如果深入原理研究还需要研究程序字节码。

第一个问题:finally语句是否一定会执行?

答案:不一定

有两种情况:(1)try之前程序就返回了 (2)try之前程序出错,导致无法向下执行。

代码清单一:

package trycatchfinallyDEMO;
public class FinallyTest {
static int test() {
int i = 1;
if (1 == i) {
return 0; //first case
}
System.out.println("previous statement");
// i /= 0; //second case
try {
System.out.println("try");
return i;
} finally {
System.out.println("finally");
}
}

public static void main(String[] args) {
System.out.println("return value is:" + test());

}

}


Output:

first case:return value is:0

second case:报错

以上两种情况,finally语句都没有得到执行。只有与finally相对应的try语句得到执行的时候finally才会执行。

第二个问题:try语句块得到执行的情况下,finally语句一定会得到执行?

答案:否定

代码清单二:

package trycatchfinallyDEMO;

public class FinallyTest {
static int test() {
int i = 1;
System.out.println("previous statement");
// i /= 0; //second case
try {
System.out.println("try");
System.exit(0);
return i;
} finally {
System.out.println("finally");
}
}

public static void main(String[] args) {
System.out.println("return value is:" + test());
}
}


Output:

previous statement

try

当一个线程在执行 try 语句块或者 catch 语句块时被打断(interrupted)或者被终止(killed),与其相对应的 finally 语句块可能不会执行。还有更极端的情况,就是在线程运行 try 语句块或者 catch 语句块时,突然死机或者断电,finally 语句块肯定不会执行了。

第三个问题:多catch如何匹配捕获

答案:按代码书写顺序寻找最接近的异常进行匹配,找到之后不再进行查找。

代码清单三:

package trycatchfinallyDEMO;

public class myException extends Exception {
public String toString(){
return "This is myException!";
}
}
package trycatchfinallyDEMO;

public class mulcatch {
static void f() throws myException {
System.out.println("throw a myException");
throw new myException();
}

static void g() throws Exception {
System.out.println("throw a Exception");
throw new Exception();
}

public static void main(String[] args) {
try {
f();// f()抛出异常得到处理后,下面的输出和g()不会得到执行。
System.out.println("**********************");
g();
} catch (myException e) {
System.out.println("first catch get it");
} catch (Exception e) {// Exception是基类,应该放在最后捕获,放在最一开始会出错。
System.out.println("second catch get it");
} finally {
System.out.println("program is end");
}

System.out.println("--------------------------------");

try {
g(); // 会被最接近的异常类型捕获
System.out.println("**********************");
f();
} catch (myException e) {
System.out.println("first catch get it");
} catch (Exception e) {//哪个catch捕获了异常就会由哪个catch处理,其他catch不执行
System.out.println("second catch get it");
} finally {
System.out.println("program is end");
}

}
}


Output:

throw a myException

first catch get it

program is end

throw a Exception

second catch get it

program is end

注意:

1、try块中,抛出异常的语句之后的语句不会得到执行。

2、Catch顺序应该是由派生到基类,由小到大捕获,Exception应该最后捕获。

3、会被最接近的异常类型捕获,一旦异常被捕获,其他catch就不会被执行。

第四个问题:finally语句和return语句执行顺序

答案:finally语句在return语句执行之后返回之前执行

在这里系统的讨论下return在try-catch-finally各语句块中的情况。

情况1: try-catch 中的return

代码清单四:

package trycatchfinallyDEMO;

public class tryandcatchwithreturn {
static int g(int i) {
try {
//i /= 0;//此处触发异常之后,就直接执行catch并返回,try里面剩下的语句不再执行。
System.out.println("g()");
return i;
} catch (Exception e) {
i += 3;
return i;
}
}

public static void main(String[] args) {
System.out.println(g(1));
}

}


Output:

g()

1

如果去掉注释输出就是4,如果注释catch当中的return就会报错,因为编译器认为try里面的return之前可能有异常产生,导致return得不到执行,所以要在函数finally或者函数尾部添加return,或者try-catch里同时添加return

情况2:try-finally中的return

代码清单五:

package trycatchfinallyDEMO;

public class tryandfinallywithreturn {
static int g(int i) {
try {
i += 2;
System.out.println("g()");
return i;
} catch (Exception e) {

} finally {
i += 5;
System.out.println(i);
//return i;
// finally里也有return,先執行try裏面的return并緩存,然后由于finally里面也有return,所以程序不再返回try进行return
// 而是直接在finally进行return
}
}

public static void main(String[] agrs) {

System.out.println(g(1));
}

}


Output:

g()

8

3

如果在finally中也添加return,那么输出为

g()

8

8

finally中无return时,程序会执行了try块中的return之后,缓存结果,然后执行finally块,最后返回缓存的结果,即使finally中对i进行了修改也没有不会反应到返回值中。如果finally里也有return的话,那么直接在finally里返回值,不在返回缓存结果。

情况3:try-catch-finally中都有return

代码清单六:

package trycatchfinallyDEMO;

public class trycatchfinallywithreturn {
static int g(int i) {
try {
i /= 0;
System.out.println("g()");
return i;
} catch (Exception e) {
i += 3;
System.out.println("catch:" + i);
return i;
} finally {
i += 5;
System.out.println("finally:" + i);
//return i;//和try-catch中return的情况一样,会缓存catch当中的return,如果finally没有return则返回缓存中的i
//如果finally中有return,则直接返回。
}
}

public static void main(String[] args) {
System.out.println(g(1));
}

}


Output:

catch:4

finally:9

4

如果在finally中添加return,那么输出为

catch:4

finally:9

9

类似于try-catch中return的情况,会缓存catch当中的return,如果finally没有return则返回缓存中的i。如果finally中有return,则直接返回。

第五个问题:返回引用的情况下呢?

代码清单七:

package trycatchfinallyDEMO;

public class recommenddemo {
static myClass myclass = new myClass();

static myClass g() {
try {
myclass.setTip("world");
return myclass;
} catch (Exception e) {
myclass.setTip("r u ok?");
return myclass;
} finally {
myclass.setTip("tencent");
//return myclass;
}
}

public static void main(String[] args) {
System.out.println(g());

}

}


Output:

hellotencent

可以看到即使finally中不进行return覆盖也会让finally块中操作反应到myclass

第六个问题:try-catch是否影响性能

情况1:不产生异常的时候

代码清单八:

package trycatchfinallyDEMO;

public class trycatchPerformance {

public static void main(String[] args) {
int result = 1;
long starttime1 = System.nanoTime();
for (int i = 0; i < 20; i++) {
result *= i;
}
long endtime1 = System.nanoTime();
System.out.println("不使用try-catch所用时间:" + (endtime1 - starttime1));
result = 1;
long starttime2 = System.nanoTime();
try {
for (int i = 0; i < 20; i++) {
result *= i;
}
} catch (Exception e) {
// TODO: handle exception
}
long endtime2 = System.nanoTime();
System.out.println("使用try-catch所用時間:" + (endtime2 - starttime2));

}

}


Output:

不使用try-catch所用时间:1555

使用try-catch所用時間:1556

实验表明在不产生异常的情况下,try-catch不会明显影响程序运行时间。

情况2:产生异常的时候

代码清单九:

package trycatchfinallyDEMO;

public class PerformanceWithEception {

public static void main(String[] args) {
int result = 1;
long starttime1 = System.nanoTime();
for (int i = 0; i < 20; i++) {
result *= i;
}
long endtime1 = System.nanoTime();
System.out.println("不使用try-catch所用时间:" + (endtime1 - starttime1));
result = 1;
long starttime2 = System.nanoTime();
try {
for (int i = 0; i < 20; i++) {
result *= i;
}
throw new mysecondException();
} catch (Exception e) {
// TODO: handle exception
}
long endtime2 = System.nanoTime();
System.out.println("使用try-catch Exception所用時間:" + (endtime2 - starttime2));

long starttime3 = System.nanoTime();
try {
for (int i = 0; i < 20; i++) {
result *= i;
}
throw new mysecondException();
} catch (myException e) {
// TODO: handle exception
}catch (Exception e) {
// TODO: handle exception
}
long endtime3 = System.nanoTime();
System.out.println("使用try-catch myException所用時間:" + (endtime3 - starttime3));

long starttime4 = System.nanoTime();
try {
for (int i = 0; i < 20; i++) {
result *= i;
}
throw new mysecondException();
} catch (mysecondException e) {
// TODO: handle exception
}catch (myException e) {
// TODO: handle exception
}
catch (Exception e) {
// TODO: handle exception
}
long endtime4 = System.nanoTime();
System.out.println("使用try-catch mysecondException所用時間:" + (endtime4 - starttime4));

}

}


Output:

不使用try-catch所用时间:622

使用try-catch Exception所用時間:22394

使用try-catch myException所用時間:2488

使用try-catch mysecondException所用時間:2177

由于多出对异常进行类型匹配以及相关处理操作,try-catch在有异常处理时,的确会消耗很多的运行时间。但是与不使用try-catch在时间上不具备可比性,因为它们是功能上的对比。

通过试验可知,catch到的异常类型越接近发生的异常越节省时间,如果单纯的用Exception去过滤会造成很大的时间开销。同时可以想到,尽量少地在try里面添加代码、尽量不在循环里使用try-catch、尽量精确地匹配异常等优化措施,从而提高性能。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: