曾经听到过关于老司机和新手程序员的区别,其中最大的一个区别就在于异常的处理。新手程序员老是天真得把世界想得太美好,基本上没想过会出现异常的状况,而一个经验丰富的老司机会把最坏的打算考虑进去,给出相应的解决办法,使得发生异常时对系统的影响下降到最小。对此,我深表认同。现实的状况老是复杂的,并且还有不少不怀好意的人时刻准备攻击你的系统。使用你系统的用户越多,这种潜在的风险也就越大。java
异常处理是应对这些风险的最强有力的武器。在Java的世界里,异常有两种:受检异常(checked exception)和非受检异常(unchecked exception)。想必全部的Javaer都使用过这两种异常,可是什么时候使用哪一个异常缺失常常困扰程序员的头疼问题。在此,我分享一下本身的见解,若是你有不一样的意见,请留意探讨。程序员
这条准则是我在决定使用Checked Exception仍是Unchecked Exception的第一原则。若是API的使用者在正常使用的过程当中都会出现异常,那么这种异常就属于Checked Exception。由于这种异常时属于程序执行流程众多分支之一,API的使用者必须意识到这种状况,并作出相应的处理。编程
举个栗子:ui
我但愿向zookeeper中建立一个节点,那么这种状况就隐含了两个前提条件:spa
那么,这个API的签名大体应该是这样:.net
void createNode(String path,byte[] data) throws FatherNodeNotExist, NodeExist;
API的使用者看到这个签名的定义时就会获得一个强烈的心理暗示,我须要考虑父节点不存在和本节点已存在的状况,那么他就不得不显示的去处理这两种异常。设计
有的朋友可能会争论说,我正常的状况下不会出现这种状况,由于使用这个API的前提就是先建立好父节点,然后建立本节点,那我就不用抛出两种异常了,使用者也轻松了许多。但事实真的如此吗?咱们想固然的认为了使用者是 本身人
,他们会乖乖的按照咱们的想法去先建立父节点,再建立本节点,若是是在一个很局限的使用场景下,每一个人都说通过严格培训的,那么你能够去作这样的假设,可是我仍是不推荐你这么作,由于这样设计使得系统是脆弱的,不稳定的。若是能经过系统能本身避免这些错误,为何不呢?何况,若是你把这个API开放给第三方的使用者,那么状况会更糟糕,你根本不知道他们会怎样去使用API,这很是恐怖!code
有时候状况会变得很复杂, 正常状况
的鉴定变得很困难,你确定会遇到这种时候,此时就须要结合你的业务场景去权衡其中的利弊。这依赖与你的经验和对业务场景的理解,我没法给你一个绝对的建议,那样是不负责任的。blog
我再举个常见的栗子:用户修改他拥有的资源信息。在菜谱APP中给出一个接口,让用户修改他菜谱的信息。那么这里一个隐含的条件就是用户修改他本身的菜谱信息,他是无权限修改别人的菜谱信息的。那么这个API的签名多是这样的:继承
void updateMenu(long menuId,long uid,String title,String description...);
若是用户尝试去修改不属于他的菜谱呢?咱们是否须要throws UserPermissionException之类受检异常?我认为是不须要的。判断是这属于正常状况吗?我认为这不算是正常状况。正常状况下,客户端调用修改信息的接口,那么menuId必定是属于这个用户的。若是出现这种状况,要么是你系统设计的就有问题,要么就是不怀好意的人在破坏你的系统。前者须要从新设计咱们的系统,然后者咱们更不用关系,直接抛出一个RuntimeException就能够,由于他不算正经常使用户。
注意这里的一个关键词是 推荐
,决定使用哪一种异常最为根本的仍是第一条原则。若是第一条原则难以判断时,才考虑调用者。这条原则和 Effective Java
中的第58条很像,若是有这本书的朋友能够再拿出来读读。
我和 Effective Java
#58不一样的观点在于,这条原则只能是 推荐
,另外,对于全部不能恢复的状况我都建议使用非受检异常。我对可恢复的理解是,若是API的调用者可以处理你抛出的异常,并给出积极的响应和反馈,并指导它的使用者作出调整,那么这就是可恢复的。不可恢复就是API的调用者没法处理你抛出的异常,或者仅仅只是打个LOG记录一下,不能对它的使用者作出提示,那么均可认为是不可恢复的。
仍是最开始的栗子,若是调用 createNode
的调用者能响应 FatherNodeNotExist
,并把这种状况反应到终端上,那么使用受检异常是有积极意义的。对于不可恢复的状况,包括编程错误,我建议都是用非受检异常,这样系统能 fail fast
,把异常对系统的影响降到最低,同时你还能得到一个完整的异常堆栈信息,何乐而不为呢?!
基本上,这两条原则就能帮你决定究竟是使用受检异常仍是非受检异常了。固然,现实的状况很复杂,须要根据你所处的具体业务场景来判断,经验也是不可或缺的。在设计API的时候多问下本身这是正常状况下出现的吗,调用者能够处理这个异常吗,这会颇有帮助的!
异常处理是一个很是大的话题,除了选择 checked exception
仍是 unchecked exception
之外,还有一些通常的通用原装,例如:
这些在 Effective Java
中都有详细的介绍,朋友能够认真读一下这本书,写的很是好!
对异常处理有不一样理解的朋友能够给我留言,一块儿讨论,共同进步!
参考文献:
Effective Java, 2nd Edition
This article used CC-BY-SA-3.0 license, please follow it.
我过去支持checked异常,可是最近我改变了个人观点。Rod Johnson(Spring Framework),Anders Hejlsberg(C#之父),Joshua Bloch(Effective Java,条目41:避免checked异常的没必要要的使用)和其余一些朋友使我从新考虑了checked异常的真实价值。最近咱们尝试在一个较大的项目中使用unchecked异常,效果还不错。错误处理被集中在了少数几个类中。会有须要本地错误处理的地方,而不是将异常传播给主错误处理代码。可是这种地方不会不少。因为代码中不会处处都是try-catch块,咱们的代码变得可读性更好。换句话说,使用unchecked异常比使用checked异常减小了无用的catch-rethrow try-catch块。总之,我建议使用unchecked异常。至少在一个工程中尝试过。我总结了如下缘由: Unchecked异常不会使代码显得杂乱,由于其避免了没必要要的try-catch块。 Unchecked异常不会由于异常声明汇集使方法声明显得杂乱。 关于容易忘记处理unchecked异常的观点在个人实践中没有发生。 关于没法获知如何处理未声明异常的观点在个人实践中没有发生。 Unchecked异常避免了版本问题。
此处连接:http://blog.csdn.net/kingzone_2008/article/details/8535287。
此处貌似很不错,异常集中处理,加入返回信息。貌似更好哦。。。我也有点支持。。。