1、异常转译的原理 所谓的异常转译就是将一种异常转换另一种新的异常,也许这种新的异常更能准确表达程序发生异常。 在Java中有个概念就是异常原因,异常原因导致当前抛出异常的那个异常对象,几乎所有带异常原因的异常构造方法都使用Throwable类型做参数,这 也就为异常的转译提供了直接的支持,因为任何形式的异常和错误都是Throwable的子类。比如将SQLException转换为另外一个新的异常 DAOException,可以这么写: 先自定义一个异常DAOException: public class DAOException extends RuntimeException { //(省略了部分代码) public DAOException(String message, Throwable cause) { super(message, cause); } } 比如有一个SQLException类型的异常对象e,要转换为DAOException,可以这么写: DAOException daoEx = new DAOException ( "SQL异常", e); 异常转译是针对所有继承Throwable超类的类而言的,从编程的语法角度讲,其子类之间都可以相互转换。但是,从合理性和系统设计角度考虑,可将异常 分为三类:Error、Exception、RuntimeException,笔者认为,合理的转译关系图应该如图 2: 图 2 异常转译 为什么要这么做呢?笔者认为,异常的处理存在着一套哲学思想:对于一个应用系统来说,系统所发生的任何异常或者错误对操作用户来说都是系统"运行时"异常,都是这个应用系统内部的异常。这也是异常转译和应用系统异常框架设计的指导原则。在 系统中大量处理非检查异常的负面影响很多,最重要的一个方面就是代码可读性降低,程序编写复杂,异常处理的代码也很苍白无力。因此,很有必要将这些检查异 常Exception和错误Error转换为RuntimeException异常,让程序员根据情况来决定是否捕获和处理所发生的异常。 图中的三条线标识转换的方向,分三种情况: ①:Error到Exception:将错误转换为异常,并继续抛出。例如Spring WEB框架中,将org.springframework.web.servlet.DispatcherServlet的doDispatch()方法 中,将捕获的错误转译为一个NestedServletException异常。这样做的目的是为了最大限度挽回因错误发生带来的负面影响。因为一个 Error常常是很严重的错误,可能会引起系统挂起。 ②:Exception到RuntimeException:将检查异常转换为RuntimeException可以让程序代码变得更优雅,让开发人员集中经理设计更合理的程序代码,反过来也增加了系统发生异常的可能性。 ③:Error到RuntimeException:目的还是一样的。把所有的异常和错误转译为不检查异常,这样可以让代码更为简洁,还有利于对错误和异常信息的统一处理。 1、 异常链 异常链顾名思义就是将异常发生的原因一个传一个串起来,即把底层的异常信息传给上层,这样逐层抛出。Java API文档中给出了一个简单的模型: try { lowLevelOp(); } catch (LowLevelException le) { throw (HighLevelException) new HighLevelException().initCause(le); } 当程序捕获到了一个底层异常le,在处理部分选择了继续抛出一个更高级别的新异常给此方法的调用者。这样异常的原因就会逐层传递。这样,位于高层的异常递 归调用getCause()方法,就可以遍历各层的异常原因。这就是Java异常链的原理。异常链的实际应用很少,发生异常时候逐层上抛不是个好注意,上 层拿到这些异常又能奈之何?而且异常逐层上抛会消耗大量资源,因为要保存一个完整的异常链信息。 注:顺着异常链可以找到原始异常: package com.cognizant.chapter9; import java.sql.SQLException; class DAOException extends RuntimeException { public DAOException(String msg, Throwable cause) { super(msg, cause); } } class MyDAOException extends RuntimeException{ public MyDAOException(String msg,Throwable cause){ super(msg,cause); } } public class TestExceptionTransform { public static void main(String[] args){ SQLException e= new SQLException(); DAOException aa= new DAOException("FirstSQLException",e); // System.out.println(aa.getCause()); MyDAOException bb= new MyDAOException("secondSQLException",aa); System.out.println(bb.getCause().getCause()); } }