Atitit 异常的实现原理 与用户业务异常
1.1. 异常的实现原理
方法调用栈(method invocation stack)来跟踪每个线程中一系列的方法调用过程。该堆栈保存了每个调用方法的本地信息(比如方法的局部变量)。每个线程都有一个独立的方法调用栈。对于Java应用程序的主线程,堆栈底部是程序的入口方法main()。当一个新方法被调用时,Java虚拟机把描述该方法的栈结构置入栈顶,位于栈顶的方法为正在执行的方法。
当一个方法正常执行完毕,Java虚拟机会从调用栈中弹出该方法的栈结构,然后继续处理前一个方法。如果在执行方法的过程中抛出异常,则Java虚拟机必须找到能捕获该异常的catch代码块。它首先查看当前方法是否存在这样的catch代码块,如果存在,那么就执行该catch代码块;否则,Java虚拟机会从调用栈中弹出该方法的栈结构,继续到前一个方法中查找合适的catch代码块。在回溯过程中,如果Java虚拟机在某个方法中找到了处理该异常的代码块,则该方法的栈结构将成为栈顶元素,程序流程将转到该方法的异常处理代码部分继续执行。当Java虚拟机追溯到调用栈的底部的方法时,如果仍然没有找到处理该异常的代码块,按以下步骤处理。
(1)调用异常对象的printStackTrace()方法,打印来自方法调用栈的异常信息。
(2)如果该线程不是主线程,那么终止这个线程,其他线程继续正常运行。如果该线程是主线程(即方法调用栈的底部为main()方法),那么整个应用程序被终止。
1.2. 用户业务异常
用户系统
Pwd_or_uname_err
User_already_exist
账户系统
Amount_not_ennagh
1.3. 异常转译和异常链
在分层的软件结构中,会存在自上而下的依赖关系,也就是说上层的子系统会访问下层系统的API。当位于上层的子系统不需要关系来自底层的异常的细节时,常见的做法是捕获原始的异常,把它转换为一个新的不同类型的异常,再抛出新的异常,把它转换为一个新的不同类型的异常,再抛出新的异常,这种处理异常的方法称为异常转译。
从面向对象的角度来理解,异常转译使得异常类型与抛出异常的对象的类型位于相同的抽象层。例如:车子运行时会出现故障异常,而职工开车上班会出现迟到异常,车子的故障异常是导致职工的迟到异常的原因,如果员工直接抛出车子的故障异常,意味着车子故障是发生在职工身上的,这显然是不合理的,正确的做法是,将在职工类里发生的车子异常转译为迟到异常。
1.4. 避免异常
应该尽可能地避免异常,尤其是运行时运行时异常。避免异常通常有两种办法:
(1)许多运行时异常是由于程序代码中的错误引起的,只要修改了程序代码的错误,或者改进了程序的实现方法,就能避免这种错误。
(2)提供状态测试方法。有些异常是由于当对象处于某种状态时,不合适某种操作而造成的。例如当高压锅内的水蒸气的压力很大,突然打开锅盖,会导致爆炸。为了避免这类事故,高压锅应该提供状态测试功能,让使用者在打开锅盖前,能够判断锅内的高压蒸汽是否排放完。在程序上,调用某个方法,可以先用状态测试功能来测试一下,满足条件才调用它,避免出现异常。
1.5. 异常恢复
保持异常的原子性有以下办法。
(1)最常见的办法是先检查方法的参数是否有效确保当异常发生时还没有改变对象的初始状态(也就是异常发生之前,检查好各个条件,确保异常不会发生才开始改变对象的状态)。
(2)编写一段恢复代码,由它来解释操作过程中发生的失败,并且使对象状态回滚到初始状态。这种办法不是很常用,主要用于永久性的数据结构,比如数据库的事务回滚机制就采取了这种办法。
(3)在对象的临时拷贝上进行操作,当操作成功后,把临时拷贝中的内容复制到原来的对象的对象中。
1.6. catch代码块中捕获异常处理流程
只要异常发生,就意味着某些地方出了问题,catch代码块既然捕获了这种异常,就应该提供处理异常的措施,比如:
(1)处理异常。针对该异常采取一些行动,比如弥补异常造成的损失或者给出警告信息等。
(2)重新抛出异常。catch代码块在分析了异常之后,认为自己不能处理它,重新抛出异常。
(3)进行异常转译。把原始异常包装为适合于当前抽象层的另一种异常,再将其抛出。
(4)假如在catch代码块中不能采取任何措施,那就不要捕获异常,而是用throws子句声明异常抛出。
java 详解异常处理原理 - Code-lover's Learning Notes - 博客频道 - CSDN.NET.html
作者:: 绰号:老哇的爪子 ( 全名::Attilax Akbar Al Rapanui 阿提拉克斯 阿克巴 阿尔 拉帕努伊 )
汉字名:艾提拉(艾龙), EMAIL:1466519819@qq.com
转载请注明来源: http://blog.csdn.net/attilax
Atiend