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

来源:互联网 发布:java的io流总结 编辑:程序博客网 时间:2024/04/30 10:55


Java的基本理念是“结构不佳的代码不能运行”
发现错误的理想时机是在编译阶段,然而,编译期间并不能找出所有的错误,余下的问题必须在运行期间解决。
1.概念
错误处理的解决方法是:用强制规定的形式来消除错误处理过程中随心所欲的因素。
2.基本异常
异常情形是指阻止当前方法或作用域继续执行的问题。
普通问题是指在当前环境下能得到足够的信息,总能处理这个错误。
异常处理程序的任务是将程序从错误状态中恢复,以使程序能要么换一种方式运行,要么继续运行下去。
2.1异常参数
所有标准异常类都有两个构造器:一个是默认构造器,另一个是接受字符串作为参数,以便能把相关信息放入异常对象的构造器
能够抛出任意类型的Throwable对象,它是异常类型的根类
3.捕获异常
监控区域:是一段可能产生异常的代码,并且后面跟着处理这些异常的代码
3.1try块
try块:在这个块里“尝试”各种(可能产生异常的)方法调用,它是跟在try关键字之后的普通程序块。
3.2异常处理程序
抛出的异常必须在某处得到处理,这个“地点”就是异常处理程序
针对每个要捕获的异常,得准备相应的处理程序。异常处理程序紧跟在try块之后,以关键字catch表示。
注意:只有匹配的catch子句才能得到执行。在try块的内部,许多不同的方法调用可能会产生类型相同的异常,而你只需要
提供一个针对此类型的异常处理程序。
终止和恢复
异常处理理论上有两种基本模型
终止模型:在这种模型中,将假设错误非常关键,以至于程序无法返回到异常发生的地方继续执行。一旦异常被抛出。就表明
错误已无法挽回,也不能回来继续执行。
恢复模型:异常处理程序的工作是修正错误,然后重新尝试调用出问题的方法,并认为第二次能成功。
程序员更倾向于终止模型,恢复模型不适用,原因是它所导致的耦合:恢复性的处理程序需要了解异常抛出的地点,这势必要
包含依赖于抛出位置的非通用性代码。这增加了代码编写和维护的困难,对于异常可能会从许多地方抛出的大型程序来说,更是如此。
4.创建自定义异常
不必拘泥于Java中已有的异常类型。java提供的异常体系不可能预见所有的希望加以报告的错误,所以可以自己定义异常类
来表示程序中可能遇到的待定问题。
5.异常说明
异常说明使用了附加的关键字throws,后面接一个所有潜在异常类型的列表
代码必须与异常说明保持一致。如果方法里的代码产生异常却没有进行处理,编译器会发现这个问题并提醒你:要么处理这个
异常,要么就在异常说明汇总表明此方法将产生异常。
注:可以声明方法将抛出异常,实际上却不抛出。
6.捕获所有异常
通过捕获异常类型的基类Execption,可以捕获所有的异常,所以最好把它放在处理程序列表的末尾,以防止它抢在其他程序之前先把异常捕获。
因为Execption是与编程有关的所有异常类的基类,所以它不会含有太多具体的信息,不过可以调用它从其基类Throwable继承的
方法:
String getMessage()
String getLocalizedMessage()
6.1栈轨迹
void printStackTrace()返回一个由栈轨迹中的元素所构成的数组。
6.2重新抛出异常
重抛异常会把异常抛给上一级环境中的异常处理程序,同一个try块的后续catch子句将被忽略。
如果只是把当前异常对象重新抛出,那么printStackTrace()方法显示的将是原来异常抛出点的调用栈信息,而非重新抛出点信息
要想更新这个信息,可以调用fillInStackTrace()方法,这将返回一个Throwable对象。它把当前栈信息填入原来那个异常对象中
6.3异常链
常常会想要在捕获一个异常后抛出另一个异常,并且希望把原始异常的信息保存下来,这被称为异常链
Throwable的子类在构造器中可以接受一个cause(因由)对象作为参数。这个cause就用来表示原始异常,这样通过把原始异常
传递给新的异常,使得即使在当前位置创建并抛出了新的异常,也能通过这个异常链追踪到异常最初发生的位置。
在Throwable的子类中,只有三种基本的异常类提供了带cause参数的构造器,它们是Error、Exceprion以及RuntimeExecption。
如果要把其他类型的异常连接起来,应该使用initCause()方法而不是构造器。
7.Java标准异常
Throwable这个Java类被用来表示任何可以作为异常被抛出的类。Throwable对象可分为两种类型:Error用来表示编译时和系统
错误;Execption是可以被抛出的基本类型。
异常的基本的概念是用名称代表发生的问题,并且异常的名称应该可以望文知意。
7.1特例RuntimeExecption
运行时异常的类型很多,它们会自动被Java虚拟机抛出,所以不必在异常说明中把它们列出来。
8.使用finally进行清理
无论异常是否被抛出,finally子句总能被执行
8.1finally用来做什么
当要把除内存之外的资源恢复到它们的初始状态时,就要用到finally子句。
当涉及break和continue语句的时候,finally子句也会得到执行
8.2在return中使用finally
因为finally子句总是会执行的,所以在一个方法中,可以从多个点返回,并且保证重要的清理工作仍旧会执行
8.3缺憾:异常丢失
遗憾的是,Java的异常实现也有瑕疵。异常作为程序出错的标志,决不应该被忽略,但是还是有可能被忽略。
用某些特殊的方式使用finally子句,就会发生这种情况。
9.异常的限制
当覆盖方法的时候,只能抛出在基类方法的异常说明里列出的那些异常。
异常限制对构造器不起作用。子类构造器可以抛出任何异常,而不必理会基类构造器所抛出的异常。派生类构造器的异常说明
必须包含基类构造器的异常说明。
10.构造器
构造器会把对象设置成安全的初始状态,但还会有别的动作,比如打开一个文件,这样的动作只有在对象使用完毕并且用户调用
了特殊的清理方法之后才能得以清理。如果在构造器内抛出了异常,这些清理行为也许就不能正常工作。
11.异常匹配
抛出异常的时候,异常处理系统会按照代码的书写顺序找出“最近”的处理程序。找到匹配的处理程序之后,它就认为异常将
得到处理,然后就不再继续查找。查找的时候并不要求抛出的异常同处理程序所声明的异常完全匹配。派生类的对象也可以
匹配其基类的处理程序。
12.其他可选方式
异常处理的原则:只有在你知道如何处理的情况下才捕获异常

0 0