深入理解java中的try-catch-finally

来源:互联网 发布:2016淘宝客赚不赚钱 编辑:程序博客网 时间:2024/06/05 10:18
  1. 首先讲一下异常的层次结构,就看下图吧:
    这里写图片描述
  2. 这么多异常,那我们写程序的时候都要try-catch 捕获么?答:非也

    那哪些异常需要我们try-catch捕获,哪些不需要try-catch捕获呢?
    通常,Java的异常(包括Exception和Error)分为可查的异常(checked exceptions)和不可查的异常(unchecked exceptions)。

    可查异常(编译器要求必须处置的异常):正确的程序在运行中,很容易出现的、情理可容的异常状况。可查异常虽然是异常状况,但在一定程度上它的发生是可以预计的,而且一旦发生这种异常状况,就必须采取某种方式进行处理。

    除了RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常。这种异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。
    不可查异常(编译器不要求强制处置的异常):包括运行时异常(RuntimeException与其子类)和错误(Error)。

    Exception 这种异常分两大类运行时异常和非运行时异常(编译异常)。程序中应当尽可能去处理这些异常。

    运行时异常:都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
    非运行时异常 (编译异常):是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。

  3. try 块:用于捕获异常。其后可接零个或多个catch块,如果没有catch块,则必须跟一个finally块。
    catch 块:用于处理try捕获到的异常。
    finally 块:无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。在以下4种特殊情况下,finally块不会被执行:
    1)在finally语句块中发生了异常。
    2)在前面的代码中用了System.exit()退出程序。
    3)程序所在的线程死亡。
    4)关闭CPU。

  4. 下面看一下我们比较熟悉的 try catch finally语句,试试下面的代码你知道正确的执行结果么?

public class TestException {      public TestException() {      }      boolean testEx() throws Exception {          boolean ret = true;          try {              ret = testEx1();          } catch (Exception e) {              System.out.println("testEx, catch exception");              ret = false;              throw e;          } finally {              System.out.println("testEx, finally; return value=" + ret);              return ret;          }      }      boolean testEx1() throws Exception {          boolean ret = true;          try {              ret = testEx2();              if (!ret) {                  return false;              }              System.out.println("testEx1, at the end of try");              return ret;          } catch (Exception e) {              System.out.println("testEx1, catch exception");              ret = false;              throw e;          } finally {              System.out.println("testEx1, finally; return value=" + ret);              return ret;          }      }      boolean testEx2() throws Exception {          boolean ret = true;          try {              int b = 12;              int c;              for (int i = 2; i >= -2; i--) {                  c = b / i;                  System.out.println("i=" + i);              }              return true;          } catch (Exception e) {              System.out.println("testEx2, catch exception");              ret = false;              throw e;          } finally {              System.out.println("testEx2, finally; return value=" + ret);              return ret;          }      }      public static void main(String[] args) {          TestException testException1 = new TestException();          try {              testException1.testEx();          } catch (Exception e) {              e.printStackTrace();          }      }  }  

输出结果:这里写图片描述
当我们注释掉finally中的return语句后结果会怎么样呢?

public class TestException {      public TestException() {      }      boolean testEx() throws Exception {          boolean ret = true;          try {              ret = testEx1();          } catch (Exception e) {              System.out.println("testEx, catch exception");              ret = false;              throw e;          } finally {              System.out.println("testEx, finally; return value=" + ret);              return ret;          }      }      boolean testEx1() throws Exception {          boolean ret = true;          try {              ret = testEx2();              if (!ret) {                  return false;              }              System.out.println("testEx1, at the end of try");              return ret;          } catch (Exception e) {              System.out.println("testEx1, catch exception");              ret = false;              throw e;          } finally {              System.out.println("testEx1, finally; return value=" + ret);              //return ret;          }      }      boolean testEx2() throws Exception {          boolean ret = true;          try {              int b = 12;              int c;              for (int i = 2; i >= -2; i--) {                  c = b / i;                  System.out.println("i=" + i);              }              return true;          } catch (Exception e) {              System.out.println("testEx2, catch exception");              ret = false;              throw e;          } finally {              System.out.println("testEx2, finally; return value=" + ret);              //return ret;          }      }      public static void main(String[] args) {          TestException testException1 = new TestException();          try {              testException1.testEx();          } catch (Exception e) {              e.printStackTrace();          }      }  }

输出结果:这里写图片描述
总结:当finally代码里面不返回(无 return 和 throw)的时候,执行catch里面的throw语句,向上一级抛出异常。

  • fillInstackTrace

再说一个方法fillInStackTrace,fillInStackTrace每次执行的时候,会清空原来的栈内的trace信息。然后在当前的调用位置处重新建立trace信息, 所以在方法b()中printStackTrace的执行结果跟c()中的是不一样的。
b()方法被c()调用,c()被a()调用,a()被main()调用, 所以在b()中fillInStackTrace时,栈内会包含b(), a(), main()的信息;而在c()中调用fillInStackTrace时,栈内的信息会被刷新为c(), a(), main()。

0 0
原创粉丝点击