第十二章 异常处理

 

    Java的异常相比于C语言这种没有错误机制的语言是一个很大的进步,但Java中的异常并没有想象中的强大。异常的初衷是能在程序运行时报告错误并从错误中恢复,但是这种恢复很少(<10%)能实现,报告功能是异常处理的精髓。

    Java坚定的强调所有的错误都以异常的形式报告这一事实

 

抛出:将错误信息传播到"更大"的环境中

 

    当抛出异常后,有几件事会随之发生。首先,同java中其他对象的创建一样,使用new 在堆上创建异常对象。然后,当前的执行路径被终止,并且从当前环境中弹出对异常对象的引用。此时,异常处理机制接管程序,并寻找一个恰当的地方来继续执行程序,这个恰当的地方就是异常处理程序,它的任务是将程序从错误状态恢复,以使程序要么换一种方式运行,要么继续运行下去

 

throw new Exception();

//new Exception()将生成一个异常对象的引用,throw接收这个引用并从当前作用域退出,throw类似于return

 

通常异常对象中仅有的信息就是异常的类型

 

catch(Exception e){                                     catch(NullPointerException e){

...                                                会在编译         ...

}                                                   期报错      }

catch(NullPointerException e){      ------>    catch(Exception e){

...                                                                     ...

}                                                                  }

                                                                    (正确的做法,先捕获小的异常)

 

恢复模型:

    使用异常处理可以是程序从错误中恢复

    while(true){

        try{

            //...

            break;

        }catch(){

        //...

        }

    }

    同时还可以定义变量在尝试n次之后从错误中退出

 

受检异常

    编译时被强制检查的异常,如 void f() throws XXException

非受检异常

    均继承自RuntionException,它们会自动被java虚拟机抛出。这种异常属于错误,将被自动捕获,但可在代码中抛出RuntimeException。当程序产生非受检异常时程序会在退出前自动调用printStackTrace()方法。非受检异常可以被捕获

 

JDK异常结构图

Throwable

    |--Error

        |--...OutOfMemoryError等    

 

    |--Exception

        |--ClassNotFoundException等

        |--RuntimeException

            |--...

 

printStackTrace() 调用栈显示了把你带到异常抛出地点的方法调用序列

 

e.fillInStackTrace() 将返回一个throwable对象,用于在catch内重新抛出异常后更新异常点信息。如果不这么做,printStackTrace将显示原来的抛出点调用栈轨道

 

在捕获异常后抛出另一种(注意是另一种)异常,将丢失原来的异常信息,使用异常链可以保存原始异常信息,e2.initCase(e)或构造器(e).

 

异常的基本概念是用名称代表发生的问题,并且异常的名称可以望问知意

 

finally

    在异常没有被当前异常处理程序捕获的情况下,异常机制也会在跳至更高的异常处理之前执行finally (break、continue、return也是)

 

    在有finally的try中执行会抛出RuntimeException的语句时,即便程序产生了异常并退出,也会在退出前执行finally子句

 

    bug:当try中的异常尚未得到处理而在finally中再次抛出异常时,finally中的异常就会替代原有的异常,导致原有异常信息丢失,或者在finally中加上return也会出现这种情况

 

异常与方法的覆盖和重载

    override时子类的方法可以比父类抛出更少的异常(甚至不抛出),但不能多于。

 

    异常说明本身并不属于方法类型的一部分,因此不能基于异常说明重载方法

 

 

除了内存的清理外,所有的清理(如文件)都不会自动产生。所以必须告诉客户端程序员,这是他们的责任。

 

构造器异常

    对于在构造阶段可能会抛出异常,并且要求清理的类,最安全的方式是使用嵌套try语句。

    try{

        in = new FileInput("1.txt"); //FileInput会在构造器中抛出异常

        //文件操作

        }finally{

            in.close();

        }

    }

    这种做法有可能在构造阶段发生异常,此时in并没有指向文件,却调用了close方法。

 

    更好的做法:

    try{

        in = ..;

        try{

            //文件操作

        }finally{

            in.close();

        }

    }catch(){

        //文件构造阶段出错,不需要关闭文件

    }

 

派生类构造器不能捕获其基类构造器所抛出的异常

 

异常处理的原则:只有在知道如何处理的情况在才捕获异常。

异常处理的目标:把错误处理代码同错误发生的地点相分离。

 

吞食则有害(harmful if swallowed)

 

强静态语言,在编译时就做类型检查的语言,java

 

反射和泛型就是用来补偿静态类型检查所带来的过多限制

 

好的程序设计语言能帮助程序员写出好程序,但无论哪种语言都避免不了程序员用他写出坏程序

 

处理异常的几种方式

    1.把异常传给控制台 main(String args[])throws XXException

        最简单而又不用写多少代码就能保护异常信息的方法。

    2.将"受检异常"转换为"非受检异常"

        当你不知道该如何去处理一个方法的异常,并且不希望吞掉异常或者打印无用信息时,可以使用异常链来抛出RuntimeException(throw new RuntimeException(e)),此时异常链会替你保存原始异常信息

       编译器不会强制你捕获RuntimeException,但你可以捕获

 

异常使用指南:见P281

    在知道如何处理的情况下才捕获异常

    ...

    ...

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值