try catch finally巩固

来源:互联网 发布:ibeer啤酒软件下载 编辑:程序博客网 时间:2024/06/11 23:41

1) Java Stacks:

 

所谓Java栈,描述的是一种Java中方法执行的内存模型,Java栈为线程私有,线程中每一次的方法调用(或执行),JVM都会为该方法分配栈内存,即:栈帧(Stack Frame),分配的栈帧用于存放该方法的局部变量表、操作栈(JVM执行的所有指令都是围绕它来完成的)、方法编译后的字节码指令信息和异常处理信息等,JVM指定了一个线程可以请求的栈深度的最大值,如果线程请求的栈深度超过这个最大值,JVM将会抛出StackOverflowError,注意,此处抛出的时Error而不是Exception。

下面我们来看一张图(引自Inside Java Virtual Machine)


由上图可知:

在一个JVM实例中(即我们运行的一个Java程序)可以同时运行多个线程,而每个线程都拥有自己的Java栈,此栈为线程私有,随着线程内方法的不断调用,线程内的栈深度不断增加,直到溢出。而当一个方法执行完毕(return或throw),该方法所对应的线程内的栈帧被JVM回收,线程内的栈深度会相应的变小,直到线程的终结。

 

2) Java的异常体系:

 

在Java的异常体系中,java.lang.Throwable是所有异常的超类,继承于Object,直接子类为Error和Exception,其中Error和RuntimeException(Exception的子类)为unchecked,即:无需用户捕获,除RuntimeException以外的其他Exception都为checked,即:用户必须捕获,否则编译无法通过。

因为Throwable处于Java异常体系的最顶层,所以Java抛出的任何Error和Exception都会被其捕获,包括StackOverflowError。

 

3) Finally到底是怎么回事?

 

Finally通常会配合try、catch使用,在每一处的try或catch将要退出该方法之前,JVM都会保证先去调用finally的代码,这里所说的退出不单单是指return语句,try或catch中异常的抛出也会导致相应方法的退出(当然,前提是不被catch捕获以及不被finally跳转)。在执行finally代码时,如果finally代码本身没有退出的语句(return或抛出异常),finally执行完毕后还会返回try或catch,由try或catch执行退出指令。

 

语言总是缺乏表现力,看代码吧。

public class TCF {        static int f1() {          try {              return 1;          } finally {              System.out.print("f1");          }      }        static int f2() {          try {              throw new Exception("try error");          } catch (Exception e) {              return 2;          } finally {              System.out.print("f2");          }      }        static int f3() {          try {              throw new RuntimeException("try error");          } catch (ArithmeticException e) {              return 3;          } finally {              System.out.print("f3");          }      }        static int f4() {          try {              throw new Exception("try error");          } catch (Exception e) {              throw new RuntimeException("catch error");          } finally {              System.out.print("f4");          }      }        static int f5() {          try {              throw new Exception("try error");          } catch (Exception e) {              throw new RuntimeException("catch error");          } finally {              System.out.print("f5");              return 5;          }      }            static int f6() {          try {              throw new Exception("try error");          } catch (Exception e) {              throw new RuntimeException("catch error");          } finally {              System.out.print("f6");              throw new RuntimeException("finally error");          }      }        public static void main(String[] args) {          System.out.println(" : " + f1());                    try {              System.out.println(" : " + f2());          } catch (Exception e) {              System.out.println(" : " + e.getMessage());          }            try {              System.out.println(" : " + f3());          } catch (Exception e) {              System.out.println(" : " + e.getMessage());          }                    try {              System.out.println(" : " + f4());          } catch (Exception e) {              System.out.println(" : " + e.getMessage());          }                    try {              System.out.println(" : " + f5());          } catch (Exception e) {              System.out.println(" : " + e.getMessage());          }            try {              System.out.println(" : " + f6());          } catch (Exception e) {              System.out.println(" : " + e.getMessage());          }      }  } 

输出如下:


解释如下:

声明:我们把每一个可以导致方法退出的点称为结束点。

 

f1方法: try中return 1代表着try方法块的结束点,jvm会在该结束点执行之前,执行finally,finally代码块本身没有结束点,所以执行完finally后会返回try方法块,然后执行讨try中的return 1,所以结果输出如上。

 

f2方法:try中throw代表着try方法块的结束点,但是由于有catch的存在,并且catch可以捕获try中抛出的异常,所以catch在某种意义上延续了try的生命周期,try catch此时组成了一个新的整体,try中的throw不再代表一个结束点,而catch中return 2此时代表try catch整体的结束点,这时没有任何语句可以延续try catch的生命周期,JVM知道try catch产生了一个结束点,将要结束方法的执行,所以JVM在这个结束点执行之前立即执行finally,因为finally没有结束点,所以finally执行完毕返回catch,然后执行该catch中的return 2,所以输出结果如上。

 

f3方法:f3和f2的区别在于f3的catch是捕获ArithmeticException,而我们在try中抛出的是RuntimeException,所以catch没能捕获该异常,也就无法延续try的生命周期,所以try的throw形成一个结束点,JVM获知try将要结束该方法的执行,所以马上调用finally,因为finally内部没有结束点,所以会返回try,然后try抛出自己的异常,输出结果如上。

 

f4方法:f4和f2本质相同,只不过f2中catch是以return 2作为自己的结束点,而f4中catch是以抛出异常作为自己的结束点,输出如上。

 

f5方法:f5和f4大部分相同,catch延续try的生命周期,try catch组成一个整体,而这个整体的结束点由catch抛出异常产生,区别就在于下面的部分,JVM知道try catch整体将要结束该方法的执行,所以马上调用finally,而在f5的finally内部有自己的结束点,即:return 5,这样finally自己就结束了整个方法的执行,而不会返回catch,由catch抛出异常,结束该方法的执行,所以会有如上的输出。

 

f6方法:f6和f5大致相同,只不过在f6的finally中是以抛出异常作为自己的结束点,进而结束方法的执行,输出结果如上。


参考:http://javcoder.iteye.com/blog/1131003

0 0
原创粉丝点击