1。用哪里出了问题,出了什么问题来命名,而 不是看谁丢了异常。如为一个ATM机取款操作设计一个异常类,使用NotEnoughMoneyException比ATMException和WithdrawException要好,因为后两者比较接近“谁丢了异常”,而NotEnoughMoneyException“则是以”哪里出了问题,出了什么问题“来命名。当然如果嫌这个异常太过具体,导致有太多异常类,也可以改用比较一般的TransactionException来代表所有交易异常,然后把”钱不够用了“当成其错误内容。
2。将低层异常转成高层所理解的异常。
不要将低层的实现异常直接跨层传递给上层的人,收到异常的人会被底层的实现细节困扰,造成不必要 的相关性。如对于一个存储配置文件的函数saveProperty,由于采用的存储方式不同(比如文件,数据库方式)当存储失败时,可能会丢出IOException或SQLException.如果直接将底层实现中的异常直接丢给上层的人,并不是好的做法,而且会暴露底层的实现方式,应该将异常转成上层调用者看得懂的异常,比如丢出PropertyManipulationException。这样一来,不管底层实现方式如何改变,都不会影响丢出异常的类型,而有助于上层调用者的异常处理设计。
3.同构型异常。有时为了减少因为异常引起的接口演进,会用一个异常类来表示某个类中所有函数可能会丢出的异常。这种异常类称为”同构型异常“,既避免了产生过多的异常类,对于每个函数产生异常的原因则可串接到这个异常类中,从而为接收到这个异常的函数提供足够的上下文信息。
未处理的异常
在实现函数功能的时候,你遇到了已查异常,是当下只想要实现正常逻辑,并不想要处理异常行为。这时候,不应该用一个空的catch块捕捉异常并忽略它,而是应该先定义一个属于RuntimeException的UnhandledException,再将捕捉到的已查异常串接在UnhandledException身上,最后丢出这个UnhandledException,用来代表该异常目前还没有被处理,如下所示:
catch(FileNotFoundException e){
throw new UnhandledException(e);
}
通道异常:对于没有在函数接口上声明已查异常的情况下,如果想抛出已查异常,可以通过将已查异常串接在RuntimeException子类异常的对象上,此异常被捕获后,可以通过检查此异常确定异常的原因。
资源清理不要放在try块里,因为try里面的语句随时可能因为异常而无法执行。资源清理要放在finally块里,而且finally块里要释放的资源绝对不能在try块里定义,而要异常处理块外定义,否则可能在finally块里读取不到相关的对象。
----------------------------重构------------------------------
Flowler在《重构》一书中建议了另一个“杀伤力”较小的方法。
重构就是每次以极小的修改步骤来改善设计。
--------------------------------------------------------
与其捕捉这一类已查异常并忽略它,不如在捕捉后将它转成UnhandledException丢出。
使用最外层try语句避免意外终止
在单个线程应用程序中,很容易找到“主程序”并在其中使用此方法,但是在多线程应用程序中,因为个别线程所产生的异常,可能不会传递到主线程,因此必须将保护的对象扩及到每一个线程,以防止其不预期终止。
》》写日志与显示错误消息可以做成公用程序。
- 以函数取代嵌套的try语句。