第十二章 通过异常处理程序

来源:互联网 发布:windows图标样式 编辑:程序博客网 时间:2024/05/10 12:24

概要

异常分为两种,一种是Error,一种是Exception。前者是系统编译时和系统错误。后者是程序代码错误。Exception的父类是Throwable。下面是重点内容:

1.throws new Exception();代表着异常抛出。其实异常抛出跟方法返回差不多,异常抛出会从该点返回一个异常类,然后结束这个方法。
2.我们会在try块后跟多个catch(Exception e)语句,值得注意的是,在前面的catch块捕获到异常后,后面的就不会再执行(这叫异常匹配),另外,对于这个异常的子类,catch也能匹配成功
3.如果一个方法在()后面写throws Exception这叫异常申明。那么在调用这个方法的时候,编译器会强制提醒你try catch。
4.我们可以通过e.printStackTrace(system.out)输出异常,值得注意的是,里面的参数代表重定向输出的流。在Throws类中有一个数组StackTrace[],输出的就是这个数组的遍历。实际上每一次方法调用的栈信息,比如A方法中调用了B方法,B方法出错了,那么这个StackTrace数组就存了方法A和方法B的信息,包括代码行等等。这就是我们为什么看到e.printStackTrace打印了方法调用层次信息的原因。
5.在异常catch(Exception e){}里面,如果直接再throws e,这个e被捕获后打印的是之前异常发生的信息。如果使用e.fillInStackTrace就会打印新的,当前这个位置的异常信息。如果我们再throws new Exception(),那么后面的catch会重新去捕获这个异常,并且打印的是当前位置抛出信息。
6.throw new RuntimeException是不需要我们捕获的(其他类型的异常都需要我们try catch),如果一直没有捕获它,它会直接传到main方法中,然后导致程序崩溃。
7.finally跟return是无关的,无论你从什么地方return,都会执行finally语句的。
8.有两种情况下会发生异常丢失:

  • try块嵌套导致的异常丢失
try{//假设我们这里执行的代码可能会抛出异常1   try{}finally{    //假设这里又抛出了新的异常2}}catch(Exception e){//这里的异常本来是异常1的,但是被异常2覆盖了}
  • finally方法中return导致的异常丢失
   throw new RuntimeException();//这里抛出了异常}finally{return;//因为这里return了,所以我们将看不到这个异常了}

6.在继承结构中,异常的抛出限制:

  • 子类构造函数中,要调用抛出基类构造的异常申明中的异常。
  • 方法重写的时候,只能抛出父类异常申明过的异常,或者这些异常的子类(考虑向上转型的时候,需要捕获的异常是基类的异常,如果这个方法子类申明的异常比基类多,那可能会没有正确捕获子类所有的异常)。
  • 如果一个类的基类存在一个方法,它和这个类实现的某个接口中申明的方法一致,那么是不允许实现接口的这个方法的,直接使用基类中的这个方法。
  • 继承某个接口申明的方法(要考虑类中是否已有这个方法,如果有的话参照上面一条)可以随意异常申明,但是在捕获的时候,要捕获接口的异常申明。
  • 异常申明不组成方法签名
  • 类在初始化的时候,如果向上转型,要强制捕获的是基类构造函数所申明的异常。

7.我们在构造器中,要特别注意异常捕获和清理,在构造器中,finally的执行要慎重,因为很有可能发生了异常,在这个类没有完成初始化的情况下去做清理工作(清理的某些东西可能没有被正确初始化)。
8.在构造器中,如果某些类在初始化到时候会产生异常,并且需要在finally中清理,那么切记不能只使用一个try finally块包裹两个对象的初始化工作。具体代码示例如下:

class NeedsCleanup {    private static long counter = 1;    private final long id = counter++;    public void dispose() {        System.out.println("i am dispose needcleanup ");    }}class ConstructionException extends Exception {}class NeedsCleanUp1 extends NeedsCleanup {    public NeedsCleanUp1() throws ConstructionException {    }}class CleanUpIdiom {    public static void main(String[] args) {        NeedsCleanup needsCleanup = new NeedsCleanup();        try {            // do somethings        } finally {            needsCleanup.dispose();// 这里执行清理        }        NeedsCleanup needsCleanup2 = new NeedsCleanup();        NeedsCleanup needsCleanup3 = new NeedsCleanup();        try {            // do somethings        } finally {            needsCleanup2.dispose();            needsCleanup3.dispose();//注意这里,因为在清理的时候不会产生异常,我们可以同时在一个try finally中清理        }        try {            NeedsCleanUp1 needsCleanUp1 = new NeedsCleanUp1();//再仔细看这里,由于我们这里的构造函数会产生异常,所以单独用了一个try块,如果我们跟上面一样,也写两个类的初始化,然后再同一个fianlly中执行清理工作,那么很有可能会因为第一个对象初始化产生了异常,而第二个对象没有初始化,然后跳到finally中直接执行没有初始化 的第二个对象的清理方法,这样会导致异常            try {                NeedsCleanUp1 needsCleanUp12 = new NeedsCleanUp1();                try {                    // do something                } finally {                    needsCleanUp12.dispose();                }            } catch (Exception e) {                e.printStackTrace();            } finally {                needsCleanUp1.dispose();            }        } catch (Exception e) {            e.printStackTrace();        }    }
0 0
原创粉丝点击