第十二章:通过异常处理错误

2017-12-01  本文已影响0人  MAXPUP

异常处理是在运行期间解决问题非方法,是java健壮性程序的基础。
异常允许我们强制程序停止运行,并告诉我们出现了什么问题,或者(理想状态下)强制程序处理问题,并返回到稳定状态。

**异常参数:
使用new在堆上创建异常对象,所有标准异常类都有两个构造器:一个默认构造器,另一个接受字符串作为参数,以便能把相关信息放入异常对象的构造器。

throw new NullPointerException("t = null");

**异常类型的根类——Throwable类。异常中仅有的信息就是异常类型(异常最重要的部分就是类名),除此之外不包含任何有意义的内容。

**捕获异常:
监控区域:一段可能产生异常的代码,并且后面跟着处理这些异常的代码。
try块:如果方法内部抛出了异常,方法将在抛出异常的过程中结束。要是不希望方法就此结束,可以在方法内设置一个特殊的块来捕获异常。
catch:抛出的异常必须在某处得到处理,这个地点就是异常处理程序,以关键字catch表示。一般将错误发送给标准错误流(System.err),因为System.out也许会被重定向。

**异常处理理论上有两种基本模型:终止模型和恢复模型。java支持终止模型,若要使用恢复模型,就需要在遇见错误的时候不能抛出异常,而是调用方法来修正错误,或者将try块放入while循环里,知道得到满意的结果。
一般使用终止模型,因为恢复性处理需要了解异常抛出的地点,需要包含依赖于抛出位置的非通用性代码,增加了代码编写和维护的困难。

**自定义异常:
自定义异常需要继承已有的异常类。

**异常说明:java提供了语法,以这种方式告知客户端程序员某个方法可能会抛出的异常类型。

void f() throws XxxException{}

代码必须与异常说明一致。
捕获所有的异常:使用基类Exception可以捕获所有类型的异常。

**栈轨迹:printStackTrace()方法所提供的信息可以通过getStackTrace()方法来直接访问,这个方法返回一个由栈轨迹中的元素所构成的数组,其中每一个元素都表示栈中的一帧。元素0是栈顶元素,即Throwable被创建和抛出之处。

**重新抛出异常:在捕获异常后,可以重新抛出它给上一级环境,异常的所有信息都得以保持。若想要更新抛出点信息,可以调用fillInStackTrace()方法。

**异常链:在捕获一个异常后抛出另一个异常,并且可以把原始异常的信息保存下来,实现是Trowable的子类在构造器中可以接受一个cause对象(原始异常)作为参数,提供此构造器的子类是Error(用于Java虚拟机报告系统错误),Exception以及
RuntimeException,若要把其他类型的异常链接起来,应该使用initCause()而不是构造器。

**Java标准异常:
RuntimeException:运行时异常,一般属于错误(由系统抛出),将被自动捕获。只能在代码中忽略此异常。这中异常也许会穿越所有的执行路径直达main()方法,然后输出给System.err。

**使用finally进行清理:无论try块中的异常是否抛出,都能得到执行。适用于把除内存之外的资源恢复到他们的初始状态时。无论在何处返回,finally都会执行。

**异常丢失:若在finally中抛出异常或返回,容易造成异常丢失。

**异常的限制:在覆盖方法的时候,只能抛出在基类方法的异常说明里列出的那些异常。但是异常限制对构造器不起作用。

**构造器:如果使用finally清理对象,但构造器抛出的异常有可能存在该对象的某些部分还没哟被成功创建,而这些部分在finally子句中却是要被清理的。

public class InputFile {
  private BufferedReader in;
  public InputFile(String fname) throws Exception {
    try{
      in = new BufferedReader( new FileReader(fname));
      // Other code that might throw exceptions
    } catch( FileNotFoundException e){
        print("Could not open" + fname);
        //没有打开,所以不用close
        throw e;
    } catch( Exception e){
        //其他的Exception就需要关闭了
        try{
          in.close();
        } catch(Exception e){
           print("in.close unsuccessful");
        }
        throw e;//重新抛出
    }  finally {
        // 不要在这里close,因为希望在对象的整个生命周期,都是打开的
    }
  }
}

**异常匹配:异常处理系统会按照代码的书写顺序找到最近的处理程序,执行,然后就不再继续查找。派生类对象也可以匹配其基类的处理程序。

**把“被检查的异常”转换为“不检查的异常”:把异常包装进RuntimeException中,保证不用处理也不会隐藏异常。可以不写try-catch语句或异常说明,直接忽略异常,让它自己沿着调用栈向上冒泡。

try{
...
} catch(IDontKnowWhatToDoWithThisCheckedException e){
  throw new RuntimeException(e);
}

上一篇 下一篇

猜你喜欢

热点阅读