第12章 通过异常处理错误

  1. 在catch语句中抛出当前异常,在外层被捕捉后调用printStackTrace打印信息时,异常发生起始地不会改变,不会更新为异常的新发生地。要想更新信息,可以调用fillInStackTrace()方法。如果是抛出另一种异常时,有关原来的异常发生点信息会丢失,剩下的是新的抛出点有关的信息:
import DataStructure.MyException;

/*
在catch语句中抛出当前异常,在外层被捕捉后调用printStackTrace打印信息时,
异常发生起始地不会改变,不会更新为异常的新发生地。
 */
public class Test02 {
    public static void f() throws Exception{
        throw new MyException();
    }

    public static void h() throws Exception{
        try {
            f();
        }catch (Exception e) {
            System.out.println("h()方法的printStackTrace:");
            e.printStackTrace(System.out);
            throw e;
        }
    }

    public static void main(String[] args) {
        try {
            h();
        }catch (Exception e) {
            System.out.println("main()方法的printStackTrace:");
            e.printStackTrace(System.out);
        }
    }
}
/* output:
h()方法的printStackTrace:
DataStructure.MyException
	at bulidfortest.Test02.f(Test02.java:11)
	at bulidfortest.Test02.h(Test02.java:16)
	at bulidfortest.Test02.main(Test02.java:26)
main()方法的printStackTrace:
DataStructure.MyException
	at bulidfortest.Test02.f(Test02.java:11)
	at bulidfortest.Test02.h(Test02.java:16)
	at bulidfortest.Test02.main(Test02.java:26)
 */


/*
要想更新信息,可以调用fillInStackTrace()方法
 */
class Test02_1 {
    public static void f() throws Exception{
        throw new MyException();
    }

    public static void h() throws Exception{
        try {
            f();
        }catch (Exception e) {
            System.out.println("h()方法的printStackTrace:");
            e.printStackTrace(System.out);
            throw (Exception) e.fillInStackTrace(); // 调用此方法的这一行就成为异常的新发生地了
        }
    }

    public static void main(String[] args) {
        try {
            h();
        }catch (Exception e) {
            System.out.println("main()方法的printStackTrace:");
            e.printStackTrace(System.out);
        }
    }
}
/* output:
h()方法的printStackTrace:
DataStructure.MyException
	at bulidfortest.Test02_1.f(Test02.java:52)
	at bulidfortest.Test02_1.h(Test02.java:57)
	at bulidfortest.Test02_1.main(Test02.java:67)
main()方法的printStackTrace:
DataStructure.MyException
	at bulidfortest.Test02_1.h(Test02.java:61)
	at bulidfortest.Test02_1.main(Test02.java:67)
 */
  1. 无论异常是否发生,finally语句都会执行。甚至在异常没有被当前的异常处理程序捕获的情况下,异常处理机制也会在跳到更高一层的异常处理程序之前,执行finally语句:
class Test02_2 {
    public static void main(String[] args) {
        try {
            try {
                // 内层没有对该异常进行捕捉。
                throw new MyException();
            }finally {
                // 在跳到上一层之前,先执行finally语句。
                System.out.println("内层finally执行");
            }
        }catch (MyException e) {
            e.printStackTrace(System.out);
        }
    }
}
/* output:
内层finally执行
DataStructure.MyException
	at bulidfortest.Test02_2.main(Test02.java:91)
*/

当涉及break和continue时,finally语句也会得到执行。

  1. 异常丢失:
public class Test01 {
    public static void main(String[] args) {
        /*
        以下程序发生了异常丢失,因为:
        1.在内层try语句中未对异常进行捕获
        2.在内层finally语句中抛出了新异常
        3.外层try语句使用Exception基类来捕获异常,未使用具体异常类。(若在内层finally语句抛出了新异常,
        并且使用了具体异常类试图在外层try语句捕捉内层被覆盖的异常,编译器将报错,错误就可避免。)
         */
        try {
            try {
                f();
            }finally {
                System.out.println("忽略了ImportantException");
                throw new TrivialException("被TrivialException代替了");
            }
        }catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    public static void f() throws ImportantException {
        throw new ImportantException();
    }
}


class ImportantException extends Exception {
    public ImportantException() {

    }

    public ImportantException(String message) {
        super(message);
    }
}

class TrivialException extends Exception {
    public TrivialException() {

    }

    public TrivialException(String message) {
        super(message);
    }
}

异常丢失可以避免:
①尽量不在finally语句中抛出异常
②使用具体异常类名来捕捉异常

  1. 当覆盖方法时,只能抛出在基类方法的异常说明里列出的那些异常,或者它们的子类。这个限制对构造器不起作用,但是派生类构造器的异常说明必须包含基类构造器的异常说明。
  2. 如果派生类继承了某个基类同时也实现了某个接口,而基类和接口中有同名但异常接口不同的方法,那么在派生类中重写该方法时可以不带异常接口,但是不能将异常接口改变为接口中方法的异常接口。
  3. 派生类的构造器不能捕获基类构造器抛出的异常,因为调用基类构造器的super语句必须位于第一位,不能被try语句包含。
  4. 异常说明本身不属于方法类型的一部分,方法类型是由方法的名字和参数的类型组成的,因此,不能基于异常说明来重载方法。
  5. 抛出运行时异常RuntimeException时,不需要对其进行处理(try…catch或者throws),可以将编译时异常用RuntimeException包装后抛出,在需要对其进行处理时,再调用getCause( )方法获得被包装的原始异常,这样编译时错误就可以被我们“忽略”了。(RuntimeException也是Exception的子类)
class Test02_3 {
    public Test02_3() {

    }

    public static void f(int type) {
        try {
            switch (type) {
                case 0 -> throw new MyException();
                case 1 -> throw new RuntimeException("where am i?");
            }
        } catch (Exception e) {
            // RuntimeException异常无需处理
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        try {
            f(1);
        }catch (RuntimeException e) {
            try {
                throw e.getCause();
            } catch (MyException me) {
                System.out.println("catch me!");
            } catch (Throwable throwable) {
                System.out.println(throwable.getMessage());
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值