java异常处理二——try-catch-finally执行顺序

来源:互联网 发布:雅思知乎 编辑:程序博客网 时间:2024/06/05 11:35
之前一直以为程序执行完try-catch-fianlly之后就退出了,而try-catch-finally之后语句块后面的代码就不会执行。重新梳理一下java异常执行的顺序。

try-catch-finally执行顺序

try-catch-finally执行顺序:
@Test
public void test1() throws Exception {
int x = 1/0;//会抛出运行时异常ArithmeticException,程序运行到这里就终止了
System.out.println("try-catch-finally之后语句块");
}
不经过异常处理的程序,一旦发生异常,程序运行就会终止当前执行过程,退出程序;所以上面的执行时不会执行打印语句的。为了防止程序遇到异常,就退出程序,java提供了异常处理机制,可以让程序异常时,可以正确的退出程序。
下面使用try-catch-finally来进行异常处理:
@Test
public void test1() {
try{
// return;
int x = 1/0;//会抛出运行时异常ArithmeticException,程序运行到这里就终止了。
}
catch (ArithmeticException e){
System.out.println("除数为零错误");
}
finally {
System.out.println("finally语句块");
}
System.out.println("try-catch-finally之后语句块");
}
结果:
除数为零错误
finally语句块
try-catch-finally之后语句块

在try语句块中发生异常时->程序停止当前执行语句->匹配catch,执行catch语句内容->执行finally->执行finally之后的语句;
程序不发生异常时->执行try块->执行finally->执行finally之后的语句;
finally 块:无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。在以下4种特殊情况下,finally块不会被执行:
1)在finally语句块中发生了异常。
2)在前面的代码中用了System.exit()退出程序。
3)程序所在的线程死亡。
4)关闭CPU。
finally语句之后的语句:当在try块或catch块中遇到return语句以及发生finally语句不能执行时,fianlly语句之后的语句块也不能执行的。try{}块中已经return了,finally语句可以执行,但其后面的语句不会执行;因为运行到return时,程序方法已经执行完了,程序正常结束,所以try-catch-finally之后语句块不会执行,但finally是程序无论是否发生异常都会执行的,所以下面代码的执行结果是:finally语句块。
@Test
public void test1() {
try{
return;
//int x = 1/0;//会抛出运行时异常ArithmeticException,程序运行到这里就终止了。
}
catch (ArithmeticException e){
System.out.println("除数为零错误");
}
finally {
System.out.println("finally语句块");
}
System.out.println("try-catch-finally之后语句块");
}
//执行结果:finally语句块
另外,如果抛出的异常在catch块中,没有与之匹配的异常处理,没有为该异常处理的catch语句,程序将直接执行finally后,退出,try-catch-finally之后语句块也不执行。若有与之对应的catch,try-catch-finally之后语句块也会执行。
@Test
public void test1() throws Exception {
try{
// return;
//int x = 1/0;//会抛出运行时异常ArithmeticException,程序运行到这里就终止了。
throw new Exception();
}
catch (ArithmeticException e){
System.out.println("除数为零错误");
}
finally {
System.out.println("finally语句块");
}
System.out.println("try-catch-finally之后语句块");
}//执行结果:finally语句块

小结:try-catch-fianlly为程序提供了在发生异常情况下的另一个执行流程,如果异常在有相应的异常处理的情况下,即有相应的catch,程序执行与正常结束一样,若没有则程序从发生异常处终止。

for循环中嵌套try-catch-fianlly

下面来看for循环中嵌套try-catch-fianlly:
public void test() throws Exception {
String[] members = new String[4];
for (int count=0;count<6;count++) {
try {
System.out.println("********第"+(count+1)+"次循环****************");
int x;
if (count == 0) x = 1/0;
if (count == 1) members[4] = "George Martin";
if (count == 2) continue;
if (count == 3) throw new Exception();
if (count == 4) break;
if (count == 5) return;
 
} catch (ArrayIndexOutOfBoundsException e) {
 
System.out.println("数组越界错误");
 
} catch (ArithmeticException e) {
 
System.out.println("除数为零错误");
 
}
/*catch (Exception e){
System.out.println("主动抛出异常");
}*/
finally {
System.out.println("finally语句块");
}
System.out.println("try-catch-finally之后语句块");
}
}

结果:
********第1次循环****************
除数为零错误
finally语句块
try-catch-finally之后语句块
********第2次循环****************
数组越界错误
finally语句块
try-catch-finally之后语句块
********第3次循环****************
finally语句块
********第4次循环****************
finally语句块

第1次循环,发生异常,执行catch,finally,try-catch-finally之后语句块正常执行,所以进行了第二次循环;第2次循环同理,第三次循环程序正常continue,执行finally语句块,但其后面的语句不会执行;但第4次循环发生异常,但没有对应的catch语句,所以执行finally,终止程序。
若注释掉count == 3的情况,结果为:
********第1次循环****************
除数为零错误
finally语句块
try-catch-finally之后语句块
********第2次循环****************
数组越界错误
finally语句块
try-catch-finally之后语句块
********第3次循环****************
finally语句块
********第4次循环****************
finally语句块
try-catch-finally之后语句块
********第5次循环****************
finally语句块

for循环中嵌套try-catch-fianlly,若try语句块包含continue,break,return语句,则try-catch-finally之后语句块不会执行。

try-for-catch-finally执行顺序

@Test
public void test2(){
try{
for (int count=0;count<4;count++) {
System.out.println("********第"+(count+1)+"次循环****************");
int x;
if (count == 0) continue;
if (count == 1) x = 1/0;
if (count == 2) throw new Exception();
if (count == 3) break;
// if (count == 4) return;
}
}catch(Exception e){
System.out.println("发生异常");
}
finally {
System.out.println("finally语句块");
}
System.out.println("try-catch-finally之后语句块");
}
结果:
********第1次循环****************
********第2次循环****************
发生异常
finally语句块
try-catch-finally之后语句块
小结:若for循环中发生异常,是在for的外部放try还是内部?如果希望本次发生异常,而不影响下次执行,即下次循环还能执行的还就把try-catch放到for循环内部,在for循环内嵌套try-catch。若希望一旦for中发生异常,就终止循环,则把try放到for循环外部。

附完整代码:
package test;
 
import static org.junit.Assert.*;
 
import org.junit.Test;
 
public class TestTryCatch {
 
@Test
public void test() throws Exception {
String[] members = new String[4];
for (int count=0;count<6;count++) {
try {
System.out.println("********第"+(count+1)+"次循环****************");
int x;
if (count == 0) x = 1/0;
if (count == 1) members[4] = "George Martin";
if (count == 2) continue;
// if (count == 3) throw new Exception();
// if (count == 4) break;
if (count == 5) return;
 
} catch (ArrayIndexOutOfBoundsException e) {
 
System.out.println("数组越界错误");
 
} catch (ArithmeticException e) {
 
System.out.println("除数为零错误");
 
}
/*catch (Exception e){
System.out.println("主动抛出异常");
}*/
finally {
System.out.println("finally语句块");
}
System.out.println("try-catch-finally之后语句块");
}
}
@Test
public void test1() throws Exception {
try{
// return;
//int x = 1/0;//会抛出运行时异常ArithmeticException,程序运行到这里就终止了。
throw new Exception();
}
catch (ArithmeticException e){
System.out.println("除数为零错误");
}
finally {
System.out.println("finally语句块");
}
System.out.println("try-catch-finally之后语句块");
}
@Test
public void test2(){
try{
for (int count=0;count<4;count++) {
System.out.println("********第"+(count+1)+"次循环****************");
int x;
if (count == 0) continue;
if (count == 1) x = 1/0;
if (count == 2) throw new Exception();
if (count == 3) break;
// if (count == 4) return;
}
}catch(Exception e){
System.out.println("发生异常");
}
finally {
System.out.println("finally语句块");
}
System.out.println("try-catch-finally之后语句块");
}
}


有return的情况下try catch finally的执行顺序 

1、不管有木有出现异常,finally块中代码都会执行;
2、当try和catch中有return时,finally仍然会执行。在return语句之前,先把返回值保存起来,无论finally中的代码有没有修改返回值,返回的值都不会改变,仍然是之前保存的值),所以函数返回值是在finally执行前确定的,然后再执行fianlly语句,执行完fianlly语句再来执行return语句;但此时若finally有return,就会造成程序提前退出,返回值不是try或catch中保存的返回值。
public int fun(){
int i = 1;
try{
i++;
return i;
}finally{
i++;
//return i; //3
}
}
结果是2。在try语句中,在执行return语句时,要返回的结果已经准备好了,就在此时,程序转到finally执行了。在转去之前,try中先把要返回的结果存放到不同于x的局部变量中去,执行完finally之后,在从中取出返回结果,因此,即使finally中对变量x进行了改变,但是不会影响返回结果。它应该使用栈保存返回值。
4、finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。
5、finally中return,调用者不会执行catch,而是当做未发生异常来执行;
package basic;
 
public class TestException2 {
public void fun1() throws Exception{
try{
int i = 1/0;//发生异常
System.out.println("fun1 , at the end of try");
}catch(ArithmeticException e){
System.out.println("fun1 catch语句执行");
throw new Exception();
}finally{
System.out.println("fun1 finally 语句执行");
//return;
}
}
public void fun2() throws Exception {
try {
fun1();
System.out.println("fun2 , at the end of try");
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("fun2 catch语句执行");
throw e;
}finally{
System.out.println("fun2 finally 语句执行");
return;
}
}
public int fun(){
int i = 1;
try{
i++;
return i;
}finally{
i++;
return i;
}
}
public static void main(String[] args){
try {
new TestException2().fun2();
System.out.println("main , at the end of try");
//System.out.println(new TestException2().fun());
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("main catch语句执行");
//e.printStackTrace();
}finally{
System.out.println("main finally 语句执行");
}
}
}

fun1 catch语句执行
fun1 finally 语句执行
fun2 catch语句执行
fun2 finally 语句执行
main , at the end of try
main finally 语句执行




0 0
原创粉丝点击