TIJ-4Edition-使用异常
作者:互联网
1、摘要
发现错误的最好时机是在编译时,在程序运行之前发现的错误容易修改,且修改的代价小。
但是,如果程序在运行时发生错误怎么办?
对于没有错误处理机制的代码,它将直接退出。
稍微改进一点,就是在退出时,返回错误码,允许人们通过错误码来检查错误。(错误码怎么设计完全取决于实现者,难以统一)
更进一步,在检测到错误发生时,进入另一套执行流程,在该执行流程中处理错误或者将错误交给上层调用者处理。
异常就是这样一个把正常执行流程和发生错误后的执行流程分开的机制。
并且,异常能够把正常的代码和处理错误的代码分离,使得代码更容易组织。
2、基本异常
抛出异常后的动作:
1、使用new在堆上建立异常对象;
2、当前执行路径被终止,从当前环境中弹出异常对象的引用;
3、异常处理机制接管程序,沿调用栈寻找能够捕获该异常的异常处理程序;
4、在异常处理程序中处理该异常
异常的参数
所有标准异常都有两个构造器,默认构造器和接受一个字符串作为参数的构造器。
该字符串可以描述该异常。可通过getLocalizedMessage()方法来取得该描述。
捕获异常:
监控区域:可能产生异常的代码,后面跟随处理异常的代码。
异常处理程序:处理监控区域中抛出的异常的代码。
异常处理程序必须紧跟在try块之后。
当异常发生时,异常处理机制负责寻找参数与异常类型匹配的异常处理程序。只有匹配的catch子句才会被执行。
try{ //可能产生异常的代码 }catch(Type1 e1){ // 处理Type1类型的异常的代码 }catch(Type2 e2){ // 处理Type2类型的异常的代码 }catch(Type3 e3){ // 处理Type3类型的异常的代码 }
异常的匹配:
沿调用栈往下找,基类类型可以匹配子类类型。
因此,Exception可匹配所有的异常。
捕获所有异常:
Exception捕获所有异常。
在捕获到异常时,可以打印发生异常时的栈轨迹(调用轨迹)。
每一个StackTraceElement都代表了一个调用层次,它包含该调用的很多消息,都可以给它打印出来。
/** * 打印调用轨迹中的方法名 */ public class WhoCalled { static void f() { // Generate an exception to fill in the stack trace try { throw new Exception(); } catch (Exception e) { for(StackTraceElement ste : e.getStackTrace()) System.out.println(ste.getMethodName()); } } static void g() { f(); } static void h() { g(); } public static void main(String[] args) { f(); System.out.println("--------------------------------"); g(); System.out.println("--------------------------------"); h(); } } /* Output: f main -------------------------------- f g main -------------------------------- f g h main *///:~
重新抛出异常:
在捕获到异常后,可以处理异常,也可以重新抛出异常。
重新抛出的异常可以和原异常不一样,也可以包装原异常。
如果只是把原异常重新抛出,打印异常调用轨迹时,是从原异常发生处开始的。
使用fillInStackTrace() 方法可以将目前的栈信息填入异常,覆盖异常原有的栈信息。
方法的异常说明:
方法的形式参数列表后面可以跟随异常说明,用来指示方法内部可能会抛出哪些异常。
可以声名抛出异常,但是在方法内部却不抛出。
在方法上添加异常说明,可以将异常传递给上层调用者。
方法的上层调用者必须处理这些异常或也抛出这些异常。
在main() 方法中抛出的异常(在main方法上添加异常说明),将传递给控制台。
异常链:
捕获到一个异常后,想抛出新的异常,但是又希望保存原始的异常信息。
这可以通过将原始异常传递给新的异常来实现,该方法创造了一个异常链,即可以通过新异常找到原始异常。
在Throwable的子类中,只有三个基本的异常类提供了带cause参数的构造器:Error、Exception、RuntimeException。
用带cause参数的构造器将原始异常作为参数创建新的异常,即可创建由新指向旧的异常链。
对于其他类型的新异常,由于没有带cause参数的构造器,只能通过initCause() 方法来封装原异常。
通过getCause() 方法可以取出原始异常。
异常和finally:
异常可以看作是一种特殊的返回。
而finally是在方法返回前一定要执行的代码。
抛出异常时,会先执行finally子句再返回。
因此,如果在finally子句中抛出异常,则会屏蔽之前的异常。
异常与构造:
如果要实现正确的构造,需要在嵌套的try-catch语句中新建对象,以便在构造失败时关闭资源。
用TWR代替!!!
3、自定义异常
通过继承已有的类来创建自定义的异常,通常选择继承相近的异常类。
对于异常来说,最重要的就是异常的名字(类名)。
4、Java异常模型结构
Throwable:
Throwable类是Java语言中所有错误和异常的超类。
Java虚拟机只能抛出作为此类(或其子类之一)实例的对象,或者可以通过Java throw语句抛出这些对象。
类似地,只有这个类或它的一个子类可以是catch子句中的参数类型。
为了对异常进行编译时检查,Throwable和Throwable的任何子类如果不是RuntimeException或Error的子类,则被视为检查异常。
Error:
错误是Throwable的一个子类,它表示一个合理的应用程序不应该试图捕获的严重问题。大多数此类错误都是异常情况。
方法不需要在其throws子句中声明在方法执行期间可能抛出但未捕获的任何错误子类,因为这些错误是不应该发生的异常情况。
也就是说,为了编译时检查异常,错误及其子类被视为未检查的异常(编译期不会检查)。
Exception:
Exception及其子类是Throwable的一种形式,表示合理的应用程序可能希望捕获的条件。
Exception和任何不属于RuntimeException子类的子类都是检查异常。
如果检查的异常可以通过方法或构造函数的执行抛出并传播到方法或构造函数边界之外,则需要在方法或构造函数的throws子句中声明。
RuntimeException:
RuntimeException是Java虚拟机正常运行期间可以抛出的异常的超类。
RuntimeException及其子类是未检查的异常。
未检查的异常不需要在方法或构造函数的throws子句中声明。
标签:4Edition,异常,子类,代码,Exception,TIJ,抛出,方法 来源: https://www.cnblogs.com/lqblala/p/15201601.html