=============================================html
原文连接: java异常处理机制 转载请注明出处!java
=============================================程序员
一款高质量系统不只仅要考虑到其功能的完备性,同时也要兼顾正确性、健壮性、可靠性、易用性、可读性(可理解性)、可扩展性、可复用性、兼容性、可移植性……而说到这里面的“健壮性”就不得不提到java的异常系统。数据库
在开发过程当中见多一些不合理使用Exception的状况,例如:
try{}包含的代码过多;
经过 catch(Excrption e)不对异常类型进行细分;
捕获了异常没有进行处理;
使用Exception对代码流程进行控制(该问题存在争议);
设计接口的时候老是在后面添加一个 throws Exception……
这样的代码也许可以使程序正常运行,在程序中也不能说是错误,只能定义为使用不合理。但对于一个高质量的系统来讲,毫无疑问,这样的代码属于劣质代码!
在开发过程当中,当一个方法中接收到参数以后,紧接着须要进行的就是对参数进行校验,检验参数的类型、取值范围等是否符合输入要求。那么若是校验失败,该如何进行处理呢?是直接return null?仍是为参数设置一个默认值?又或者直接throws抛出异常?
若是抛出异常,是该抛出受检异常仍是抛出运行异常?若是抛出运行异常,那么又改如何选择抛出异常的类型呢?要想弄明白这些问题,就须要了解java的异常系统。
java中全部的可抛出结构根据类型来划分可分为两种:
Error:虚拟机错误,此种错误的发生通常比较严重,程序中没法捕获也不需进行处理。发生该错误只有一种结果——线程退出,若是该线程是main线程,则该程序结束。若是发生该错误就须要去查找触发点,优化程序。例如:VirtualMachineError,IOError。
Exception:全部的Exception都是能够进行捕获处理的,可是根据是否须要进行强制捕获可分为受检异常(强制捕获/抛出)和运行时异常(无强制要求)。
运行时异常主要为RunTimeException及其子类,除此以外都为受检异常。
受检异常若是不进行捕获或抛出则没法进行编译。如图:post
对于error,咱们不用太过于关注,该错误的产生不属于程序中的问题,不受开发者控制。所以在这里不进行讨论。
对于Exception,咱们须要搞清楚如下几个问题:
一、Exception从哪里来的?
二、如何处理捕获到的Exception?
三、如何抛出Exception?
关于第一个问题:Exception从哪里来的?
a)底层抛上来的。
在调用方法的时候,有些方法会抛出checkedException,这种受检异常须要进行强制处理,要么经过try catch进行捕获,要么继续上抛。
b)在本方中主动抛出的。
当该方法在执行过程的时候发现未知足正常执行的条件,这时就能够选择主动new一个Exception进行主动抛出。
例如,在对参数进行校验的时候发现参数为null,则能够主动抛出一个NullPointException;若是参数取值范围不符合要求,则能够主动抛出IllegalArgumentException。
关于第二个问题:如何处理捕获到的Exception?
对于捕获到的Exception大部分都是底层抛出的checkedException,由于对于UnChecketException没有必要捕获,即便捕获了也没法进行处理
那么对于捕获到了checkedException,咱们该如何处理呢?
对该异常进行判断,若是在本方法中能够进行处理,那么就在本方法中进行处理。若是在本方法中没法处理,那么就根据抛出策略进行抛出
不须要上抛的状况:修改数据库提交事务,若是发生异常则在catch中进行事务回滚。这种状况就是能够在本方法进行事务处理,不须要进行上抛。
而本方法没法处理,须要抛出异常,那么该如何抛出呢?是抛出UnChecketException仍是checketException?
关于第三个问题:如何抛出Exception? 抛出策略是什么?
这里就是问题的难点,如何定义这个抛出策略?
程序员有一个通病,老是喜欢找一个万能准则,任何问题根据该准则都能找到解决方案。可不少问题是没有明确答案的,致使在抛出策略中找不到一个万全之策。
抛出策略主要的矛盾是:当本方法没法处理异常须要进行抛出的时候,是抛出UnChecketException仍是checketException?
我我的认为,先判断上层是否有办法处理,若是有办法处理则抛出CheckedException,若是没有办法处理,解决该异常,则直接抛出UnCheckedException。可依旧存在主观的问题:如何判断上层是否可以解决该异常呢?
例如:优化
public FileInputStream(File file) throws FileNotFoundException { ..... if(filePath == null) { throw new NullPointerException();//文件路径为null则抛出UnCheckedException } else if(file.isInvalid()) { throw new FileNotFoundException("Invalid file path");//找不到文件则抛出CheckeException } .... }
在该方法中,使用上面的抛出策略不太合适,由于没办法证实调用处能够解决FileNotFoundException而解决不了NullPointerException.....
在网上找答案的时候偶然间看到一个关于该问题的帖子,才发现原来早在十四年前就已经有一批人激烈的讨论过这个问题,并从2003年周一至讨论到2007年,持续了四年,最终被关闭讨论才结束。帖子连接:为何 Java 中要使用 Checked Exceptions
帖子中讨论的异常激烈,各抒己见,能够称得上百家争鸣!每种观点都有存在的道理,可最终好像也没有找到答案,不过在里面有一我的的观点挺认同的:因此没法处理的异常都使用UnCheckedException进行抛出,不要花费精力去精心设计如何抛出。
他举了一些观点支持这个结论:【tianya】论据, 这里就不在此纠结了,相信每一个认真思考该问题的都会有本身的见解的。
写到这里突然有个想法,是否是咱们关注的点错误了?UnCheckedException 和CheckedException的表现区别在因而不是受编译机制的检查,若是想要被编译机制检测,那么就使用CheckedException,不然使用UnCheckedException。也就是说,若是须要调用者关注该异常,那么就使用CheckedException强制调用者进行关注并处理,若是不须要调用者关注,那么就使UnCheckedException。
若是是这样的话,问题便很清晰了,在实现方法的时候,对于底层上抛的CheckedException,若是可以解决则进行捕获解决,若是解决不了就直接throws继续上抛。对于主动抛出的异常,若是须要调用者关注并处理则抛出CheckedException,若是不须要则抛出UnCheckedException。而是否须要调用者关注该异常,就有本方法的实现者来决定了,无需考虑其余。这个抛出策略仍是能够的!
关于其余的,在《Effective Java》中关于异常做者提出了一个观点:一、努力使失败保持原子性。在执行过程当中若是发生异常,在退出以前应该使 异常发生以前修改的数据恢复到修改以前,以避免数据错误!!!这个问题仍是比较严重的,值得重点关注。url
---END---spa