java 异常与错误处理

  在C和C++里,程序员必须非常小心编写代码,对于程序发生的错误尤其是运行时未知的,必须得加以各种判断以避免程序错误,这带来了程序的复杂性和开发人员无比痛苦。有没办法使得业务层级错误统一能集中处理,而开发人员能集中处理正常业务代码呢?答案肯定是有,引用异常捕获机制。在现代高级语言里,异常捕获机制是必备的。

  java中的错误基类是Throwable,Throwable又分为两大类,Error和Exception。Error是系统级的错误,比如JVM发生内存错误,这时我们一般不用处理这类错误,也处理不了。Exception是异常,是针对业务上发生的异常做处理。所有异常类都继承于Exception。

  一、语法定义:

  try {

    // 业务处理代码

  } catch(异常类) {

    // 处理异常逻辑

  } catch (异常父类) {

    // 处理异常逻辑

  } finally {

    // 无论有没发生异常,这里都会执行,主要用来关闭一些资源

  }

  由上面的语法可看出,凡是try里的代码发生有异常,则会终止运行并往上抛出,它会自动匹配catch里的异常,找到合适异常会执行异常里的逻辑代码,当然也可以再往上一级抛,则使用throw e; (注:多种异常处理,一定要从子类开始,否则会有编译错误)

  

  二、异常说明:

  在java方法体里,如有明显的抛出异常,必须为该方法声明对应的异常说明(除RuntimeException外,因为运行时异常只在运行时才能检测到)。异常说明用throws关键字,如果有多个则用,分隔。具体代码如下:

  void fun() throws IOException, IllegalClassFormatException {

    if (true) {

      throw new IOException();

    } else {
      throw new IllegalClassFormatException();

    }

  }

  当然,也可以直接用一父类代替,如下:

  void fun() throws Exception

  ...

 

  如果是RuntimeException以及它的子类,则不用写异常说明。

 

  三、异常堆栈:

  在每一层级抛出异常时,会记录每一层级的异常信息,这个层级称为帧,每一帧通常代表一个方法,在java里用StackTraceElement堆栈跟踪元素表示,包含信息有发生类名,方法名,行号,文件名等。可通过异常里的getStackTrace()获取数组。代码如下:

  class Test {

    private static void exec1() {
      exec2();

    }

    private static void exec2() {

      throw new RuntimeException();

    }

    public static void main(String[] args) {

      try {

        exec1();

      } catch (Exception e) {

        StackTraceElement[] exData = e.getStackTrace(); // 0: exec2的帧, 1:exec1的帧,2: main的帧

      }

    }

  }

  堆栈跟踪信息都是从最底层异常为出发点,一层层往上抛,直到有catch捕获为止;如果需要在exec1为出发点,则使用fillInStackTrace()方法即可,如代码:

  void exec1() {

    try {

      exec2();

    } catch(RuntimeException e) {

      throw (RuntimeException)e.fillInStackTrace();

    }

  }

  这时则完全抛弃了exec2的帧,但有时我们需要查找根源,java里还有个cause属性可记录由哪里发起的异常,可在构造器里设置,在客户端要通过getCause()获取,如下:  

  void exec1() {

    try {

      exec2();

    } catch(RuntimeException e) {

      throw new RuntimeException(e);

    }

  }

 

  四、自定义异常:

  java已经提供足够丰富的异常类给我们处理,但很多时候针对业务不同,现有的异常类往往不同满足我们,这时就需要自定义异常类。所有自定义异常类都必须继承于Exception根类,(不要继承Throwable,因为此类还包含Error类,Error不是我们要处理的类)。自定义异常类原则上取最接近的现有异常类。

posted @ 2016-04-27 16:07  司马逍遥  阅读(553)  评论(0)    收藏  举报