很多次的经验教训,让我不得不重视异常处理。经常遇到的问题如下:
1)日志不准确,错误原因难以查明!!
2)日志量太大,查找麻烦!!
3)哪里需要记录日志,哪里不用记录日志?往往随心所欲!!
分析以上问题,深入研究,其实是缺少一个处理异常的原则和一个智能的机制去“加工日志”。

举个真实例子:

[10/28/13 23:42:29:009 CST] 0000004d SystemErr     R org.springframework.transaction.TransactionSystemException: Could not roll back JDBC transaction; nested exception is com.ibm.websphere.ce.cm.ObjectClosedException: DSRA9110E: Connection is closed.
[10/28/13 23:42:29:010 CST] 0000004d SystemErr R at org.springframework.jdbc.datasource.DataSourceTransactionManager.doRollback(DataSourceTransactionManager.java:279)
[10/28/13 23:42:29:010 CST] 0000004d SystemErr R at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:823)
[10/28/13 23:42:29:010 CST] 0000004d SystemErr R at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:800)
[10/28/13 23:42:29:010 CST] 0000004d SystemErr R at org.springframework.transaction.interceptor.TransactionAspectSupport.completeTransactionAfterThrowing(TransactionAspectSupport.java:339)
[10/28/13 23:42:29:010 CST] 0000004d SystemErr R at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
[10/28/13 23:42:29:010 CST] 0000004d SystemErr R at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
[10/28/13 23:42:29:011 CST] 0000004d SystemErr R at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
[10/28/13 23:42:29:011 CST] 0000004d SystemErr R at $Proxy53.deleteSsoTicketByStId(Unknown Source)
[10/28/13 23:42:29:011 CST] 0000004d SystemErr R at com.proj.sso.ca.ServiceTicketServiceImpl.destroyServiceTicket(ServiceTicketServiceImpl.java:72)
[10/28/13 23:42:29:011 CST] 0000004d SystemErr R at com.proj.sso.ca.action.SsoAction.execute(SsoAction.java:253)
[10/28/13 23:42:29:011 CST] 0000004d SystemErr R at sun.reflect.GeneratedMethodAccessor178.invoke(Unknown Source)
[10/28/13 23:42:29:011 CST] 0000004d SystemErr R at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
[10/28/13 23:42:29:011 CST] 0000004d SystemErr R at java.lang.reflect.Method.invoke(Method.java:600)
[10/28/13 23:42:29:011 CST] 0000004d SystemErr R at com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:450)
[10/28/13 23:42:29:011 CST] 0000004d SystemErr R at com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:289)
[10/28/13 23:42:29:011 CST] 0000004d SystemErr R at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:252)
[10/28/13 23:42:29:011 CST] 0000004d SystemErr R at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:256)
[10/28/13 23:42:29:011 CST] 0000004d SystemErr R at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[10/28/13 23:42:29:011 CST] 0000004d SystemErr R at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:167)
[10/28/13 23:42:29:012 CST] 0000004d SystemErr R at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
[10/28/13 23:42:29:012 CST] 0000004d SystemErr R at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[10/28/13 23:42:29:012 CST] 0000004d SystemErr R at com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:265)
[10/28/13 23:42:29:012 CST] 0000004d SystemErr R at org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:68)
[10/28/13 23:42:29:012 CST] 0000004d SystemErr R at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
[10/28/13 23:42:29:012 CST] 0000004d SystemErr R at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[10/28/13 23:42:29:012 CST] 0000004d SystemErr R at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:138)
[10/28/13 23:42:29:012 CST] 0000004d SystemErr R at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[10/28/13 23:42:29:012 CST] 0000004d SystemErr R at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:239)
[10/28/13 23:42:29:012 CST] 0000004d SystemErr R at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
[10/28/13 23:42:29:012 CST] 0000004d SystemErr R at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[10/28/13 23:42:29:012 CST] 0000004d SystemErr R at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:239)
[10/28/13 23:42:29:012 CST] 0000004d SystemErr R at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
[10/28/13 23:42:29:013 CST] 0000004d SystemErr R at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[10/28/13 23:42:29:013 CST] 0000004d SystemErr R at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:191)
[10/28/13 23:42:29:013 CST] 0000004d SystemErr R at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[10/28/13 23:42:29:013 CST] 0000004d SystemErr R at org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:73)
[10/28/13 23:42:29:013 CST] 0000004d SystemErr R at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[10/28/13 23:42:29:013 CST] 0000004d SystemErr R at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:91)
[10/28/13 23:42:29:013 CST] 0000004d SystemErr R at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[10/28/13 23:42:29:013 CST] 0000004d SystemErr R at org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:252)
[10/28/13 23:42:29:013 CST] 0000004d SystemErr R at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[10/28/13 23:42:29:013 CST] 0000004d SystemErr R at com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:100)
[10/28/13 23:42:29:013 CST] 0000004d SystemErr R at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[10/28/13 23:42:29:013 CST] 0000004d SystemErr R at com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:141)
[10/28/13 23:42:29:013 CST] 0000004d SystemErr R at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[10/28/13 23:42:29:013 CST] 0000004d SystemErr R at com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:145)
[10/28/13 23:42:29:013 CST] 0000004d SystemErr R at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[10/28/13 23:42:29:014 CST] 0000004d SystemErr R at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:171)
[10/28/13 23:42:29:014 CST] 0000004d SystemErr R at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
[10/28/13 23:42:29:014 CST] 0000004d SystemErr R at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[10/28/13 23:42:29:014 CST] 0000004d SystemErr R at com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:161)
[10/28/13 23:42:29:014 CST] 0000004d SystemErr R at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[10/28/13 23:42:29:014 CST] 0000004d SystemErr R at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164)
[10/28/13 23:42:29:014 CST] 0000004d SystemErr R at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[10/28/13 23:42:29:014 CST] 0000004d SystemErr R at com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:193)
[10/28/13 23:42:29:014 CST] 0000004d SystemErr R at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[10/28/13 23:42:29:014 CST] 0000004d SystemErr R at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:189)
[10/28/13 23:42:29:014 CST] 0000004d SystemErr R at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[10/28/13 23:42:29:014 CST] 0000004d SystemErr R at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:54)
[10/28/13 23:42:29:015 CST] 0000004d SystemErr R at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:563)
[10/28/13 23:42:29:015 CST] 0000004d SystemErr R at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77)
[10/28/13 23:42:29:015 CST] 0000004d SystemErr R at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:99)
[10/28/13 23:42:29:015 CST] 0000004d SystemErr R at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:188)
[10/28/13 23:42:29:015 CST] 0000004d SystemErr R at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:116)
[10/28/13 23:42:29:015 CST] 0000004d SystemErr R at com.proj.webc.framework.XSSDefendFilter.doFilter(XSSDefendFilter.java:69)
[10/28/13 23:42:29:015 CST] 0000004d SystemErr R at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:188)
[10/28/13 23:42:29:015 CST] 0000004d SystemErr R at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:116)
[10/28/13 23:42:29:015 CST] 0000004d SystemErr R at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:96)
[10/28/13 23:42:29:015 CST] 0000004d SystemErr R at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
[10/28/13 23:42:29:015 CST] 0000004d SystemErr R at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:188)
[10/28/13 23:42:29:015 CST] 0000004d SystemErr R at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:116)
[10/28/13 23:42:29:016 CST] 0000004d SystemErr R at com.ibm.ws.webcontainer.filter.WebAppFilterChain._doFilter(WebAppFilterChain.java:77)
[10/28/13 23:42:29:016 CST] 0000004d SystemErr R at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:908)
[10/28/13 23:42:29:016 CST] 0000004d SystemErr R at com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:997)
[10/28/13 23:42:29:016 CST] 0000004d SystemErr R at com.ibm.ws.webcontainer.extension.DefaultExtensionProcessor.invokeFilters(DefaultExtensionProcessor.java:985)
[10/28/13 23:42:29:016 CST] 0000004d SystemErr R at com.ibm.ws.webcontainer.extension.DefaultExtensionProcessor.handleRequest(DefaultExtensionProcessor.java:905)
[10/28/13 23:42:29:016 CST] 0000004d SystemErr R at com.ibm.ws.webcontainer.webapp.WebApp.handleRequest(WebApp.java:3826)
[10/28/13 23:42:29:016 CST] 0000004d SystemErr R at com.ibm.ws.webcontainer.webapp.WebGroup.handleRequest(WebGroup.java:276)
[10/28/13 23:42:29:016 CST] 0000004d SystemErr R at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:931)
[10/28/13 23:42:29:016 CST] 0000004d SystemErr R at com.ibm.ws.webcontainer.WSWebContainer.handleRequest(WSWebContainer.java:1583)
[10/28/13 23:42:29:016 CST] 0000004d SystemErr R at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:186)
[10/28/13 23:42:29:016 CST] 0000004d SystemErr R at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:455)
[10/28/13 23:42:29:017 CST] 0000004d SystemErr R at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewInformation(HttpInboundLink.java:384)
[10/28/13 23:42:29:017 CST] 0000004d SystemErr R at com.ibm.ws.http.channel.inbound.impl.HttpICLReadCallback.complete(HttpICLReadCallback.java:83)
[10/28/13 23:42:29:017 CST] 0000004d SystemErr R at com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:165)
[10/28/13 23:42:29:017 CST] 0000004d SystemErr R at com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217)
[10/28/13 23:42:29:017 CST] 0000004d SystemErr R at com.ibm.io.async.AsyncChannelFuture.fireCompletionActions(AsyncChannelFuture.java:161)
[10/28/13 23:42:29:017 CST] 0000004d SystemErr R at com.ibm.io.async.AsyncFuture.completed(AsyncFuture.java:138)
[10/28/13 23:42:29:017 CST] 0000004d SystemErr R at com.ibm.io.async.ResultHandler.complete(ResultHandler.java:204)
[10/28/13 23:42:29:017 CST] 0000004d SystemErr R at com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:775)
[10/28/13 23:42:29:017 CST] 0000004d SystemErr R at com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:905)
[10/28/13 23:42:29:017 CST] 0000004d SystemErr R at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1550)
[10/28/13 23:42:29:017 CST] 0000004d SystemErr R Caused by: com.ibm.websphere.ce.cm.ObjectClosedException: DSRA9110E: Connection is closed.
[10/28/13 23:42:29:018 CST] 0000004d SystemErr R at com.ibm.ws.rsadapter.jdbc.WSJdbcWrapper.createClosedException(WSJdbcWrapper.java:110)
[10/28/13 23:42:29:018 CST] 0000004d SystemErr R at com.ibm.ws.rsadapter.jdbc.WSJdbcConnection.rollback(WSJdbcConnection.java:3207)
[10/28/13 23:42:29:018 CST] 0000004d SystemErr R at org.springframework.jdbc.datasource.DataSourceTransactionManager.doRollback(DataSourceTransactionManager.java:276)
[10/28/13 23:42:29:018 CST] 0000004d SystemErr R ... 91 more

 

日志不准确,比如:

try{

......此处省略200行

}catch{

throw new RuntimeException("操作失败!");

}

这种日志是不准确的,很糟糕。另一种:

try{

......此处省略200行

}catch{

throw new RuntimeException( e );

}

更糟糕。层层包装之后e变得面目全非,很难识别真正的出错原因。

我新设计的日志包装类,ExceptionWrapper,可以将错误信息进行包装,既便是多次包装后,也不会失真。而且,对错误信息和栈信息可以进行定制。非常实用。

一、异常处理的基本步骤

以工具类为例,因为工具类是公用的,所以一般情况,不应该在工具类里面写日志,而应该把错误信号和错误信息抛给外层,让外层去决定:

1.  是否记录错误日志?

2.  如何后续处理?

因此,工具类的错误处理机制,要包含两个信息:

1. 异常信息,2. 成功与否的标志。

1)异常信息:有两种方法,(1)通过throw抛出,(2)返回错误对象,比如定义一个ResultBean,把错误对象塞进去。

2)成功与否的标识:(1)通过是否抛出异常来判断;(2)可以通过返回状态位表示,例如返回true代表成功,返回false代表失败。

我们先讨论throw错误这种情况。至于(2)那种情况,可应用我的OPGA设计模式,再此先不讨论。

对于throw出来的错误信息,应该是完整的、清晰的。

错误信息有两种形态,一种是自定义new出来的异常,通常业务逻辑异常,比如 age < 0 之类的。第二种,是内部程序出现错误时直接抛出来的异常,比如 0/6 ,通常是未知其具体类型的。

对于这两种错误形态,我们的处理方式也有着不同。比如对于我们自定义的异常,捕捉到之后,我们只需要getMessage,打印出message则一目了然。但是对于无法预料的错误类型,我们不但要打印出message,还要打印出异常的类型和栈信息。

还比如,对于自定义的异常,

1)假设定义一个NoLogRuntimeException,在方法的内部记录日志,比如Action--Logic--Service--DAO四层结构,在Service层中记录错误信息,然后再抛出一个NoLogRuntimeException。

2)Action层try-catch一切的错误,如果发现是NoLogRuntimeException,则不再记录日志(因为在Service层已经记录过了),否则认为是“未知的错误”,打印具体的异常类型和异常堆栈。

=========================================================

二、下面是这个问题的详细研究:

1、如何记录日志和调试信息

举个例子:

如果在dao层log了日志,又throw了错误,service层捕捉到错误后,又log日志,这样就造成了日志重复。这是我们经常看到的情景。

如果在dao层不记录日志,只是throw错误,那么“dao层”偷懒,造成的后果是,所以调用该dao的service,都要去log日志,原本“一个人的工作”,现在每个人都要做,是否麻烦!!

注意到另外一个问题,捕捉错误应该尽量精确,最好是在哪儿出错了,就在哪儿记录,这样能够定位到错误所在的“行号”。这样的错误信息,才是最有价值的。可惜我们经常把错误层层转换,层层上抛,结果“面目全非”,根本不知道底层到底发生了什么错误。例如,一个大大的try-catch:

try{

......此处省略200行

}catch{

throw new RuntimeException("操作失败!");

}

这样的写法真的很糟糕,因为操作失败的真正原因被掩盖了,在外层捕捉到这个异常后,只知道是在这个方法内部出现了错误,错误的原因是“操作失败!”。

稍微聪明一点的编程人员,会这么做:

try{

......此处省略200行

}catch{

throw new RuntimeException("操作失败!原因:" + e.getMessage() );

}

这样做是不够好的,因为原始堆栈信息丢失了,仅仅通过errorMsg是很难定位的。

再改进一下,写成:

try{

......此处省略200行

}catch{

throw new RuntimeException( e );

}

想想,这样做又是很苦嘛!非要转换一下,还不如直接抛出异常:

try{

......此处省略200行

}catch{

throw e;

}

这样做还有意义吗,还不如去掉try-catch,…………

意识到问题的普遍性,我们如何来设计这样的程序?

有人推荐:“尽量清楚的捕捉异常,try-catch要定位精准”。

在我看来,有利有弊,try-catch范围越小,意味着我们需要写更多的try-catch,以前一个try-catch就搞定了,现在要写很多的try-catch,而且写起来很烦!try-catch范围越小,遗漏的异常就越多,说不定哪个地方没有捕捉到,就报空指针了……经常被坑,有没有?

我研究这个错误处理机制大半年了,实施了很多种方案。目前探索出一条最佳的实践路线。

先介绍一种初步改进过的方法:

1)对于自己定义的异常,比如age<0这种,做法如下:

throw  new RuntimeException( xxxxxxxxxxxxxxxxxx );

把错误的原因描述清楚,更重要的是,要说明出错时的环境!比如在操作某个订单时,出错,那么这个订单的ID是多少,也要一并打印出来。还比如出错时的sql和参数是什么,错误发生的时间等等,都一并记录。即“记录错误的原因和当时的环境状态”。

2)对业务、逻辑异常,用自定义的异常,其他异常,一般情况下,不要转换成自定义的异常。对于其他的异常,应该采用直接抛出的方式。(转换之后错误信息不清晰)

一般情况下,出错了,直接抛出即可,满足大多数的情景。还有少数情况下,出错了,不希望程序退出,可以在内部捕捉。也就是在某些地方,允许出错,正确时有正常的处理流程,出错时有出错时的处理流程。这样,捕捉到的错误时,根据需要,记录日志信息,日志级别应该是debug或者warn级别的,尽量别定义成error级别,因为这种错误,是可以预料的,而且针对错误程序会自动进行处理,而error级别的错误,应该是一个最终的错误,导致程序没办法进行处理了,直接退出的那种错误。

同样以Action--Logic--Service--DAO四层结构为例,

Action是最外层,我们在最外层做最终的日志处理。

公用的dao层throw错误,把错误throw出去,不要自己处理。

同理,service层和logic层,一般都负责把错误信息传递给最外层Action,而不自己处理( 对于某些可以处理的异常,比如业务逻辑异常,需要在内部处理 )。

action负责try-catch一切内部异常,然后记录日志。(在最外层最好要捕捉全面)

再进一步实践,会发现,强制性地定义非运行时异常(比如Exception)是一种野蛮型的做法。为什么非得让别人去捕捉异常?异常出现的几率本来就小,实际上很多时候别人根本去不想去处理,大不了偶尔出了抛出未捕获的异常(由JVM或者Web容器自己去处理好了)。

因此,在这个层次上讲,比较好的方法是:通常,我们只使用运行时异常——RuntimeException及其子类,它不强制性地要求别人去捕捉,出了错,程序退出就OK了。

回过头来看非运行时Exception异常,虽然具有强制性,一般不推荐使用,但是如果有特殊需要,比如要“提醒调用者,这个方法出错后要进行一些特殊处理”,比如:

public int write(InputStream in) throws IOException;

我这个write方法是想提醒调用者,一定要及时捕捉它的异常信息,如果出了错,要进行一些特殊处理(即,关闭io流),以免造成一些垃圾残留或者其他影响。

基于这样的目的,我才推荐使用强制性的错误声明,否则,最好用RuntimeException。

另外,以示和系统RuntimeException的区别,我建议,在项目中自定义一个RuntimeException,比如B2BRuntimeException。另外,对于一些大型的模块,还可以单独定义一些有针对性的Exception类型。(当然,如果你有精力,可以多定义一些特定的错误类型,比如SourceNotFindException……)

除此之外,我透露一下我的一个工具(本文不做深入介绍),定义一个ExceptionWrapper,用于包装异常,比如以前的做法:

try{

......

}catch{

throw new RuntimeException( e );

}

如果要将Exception转换成RuntimeExcption,现在的做法是:

try{

......

}catch{

throw new ExceptionWrapper ( e );

}

这两种做法效果是大不相同的,第一种做法,用RuntimeException去包装,效果不理想,举个例子:

原始的错误栈信息如下:

java.lang.ArithmeticException: / by zero

at org.zollty.framework.mvc.handler.support.AA.ccc(AA.java:25)

at org.zollty.framework.mvc.handler.support.AA.main(AA.java:60)

经过RuntimeException包装后,错误栈信息变成了:

java.lang.RuntimeException: java.lang.ArithmeticException: / by zero

at org.zollty.framework.mvc.handler.support.AA.ccc(AA.java:28)

at org.zollty.framework.mvc.handler.support.AA.main(AA.java:60)

Caused by: java.lang.ArithmeticException: / by zero

at org.zollty.framework.mvc.handler.support.AA.ccc(AA.java:25)

... 1 more

这还只是一次包装,如果经过层层包装,栈信息量就更大!

对于这种一大串的报错信息,很难抓住重点,而且是根本没有必要的。

通过原始信息,我们很容易定位:

是at org.zollty.framework.mvc.handler.support.AA.ccc(AA.java:25)出错了。

但是经过RuntimeException包装后,变成了:

at org.zollty.framework.mvc.handler.support.AA.ccc(AA.java:28)

这是错误经过包装后throw出来的位置,而不是错误最原始的位置,要从Caused by:去寻找,才找得到源头。

既然,存在这个问题,我们能不能把它变得更简单一些呢。当然可以了。就是我设计的那个ExceptionWrapper(错误包装器),这个东西可以存放原始的错误对象(即把e存起来),重新了getMessage等方法,当你调用它的方法时,实际上获取的是最原始的错误信息。也就是说,经过了ExceptionWrapper的包装后,错误信息不会失真。打印出来,还是

java.lang.ArithmeticException: / by zero

at org.zollty.framework.mvc.handler.support.AA.ccc(AA.java:25)

at org.zollty.framework.mvc.handler.support.AA.main(AA.java:60)

而且,你还可以这样用:加入提示信息(prompt)

try{

......

}catch{

throw new ExceptionWrapper(e, "文件删除失败");

}

然后打印错误时,会附加上你的提示信息:

文件删除失败 Caused by:

java.lang.ArithmeticException: / by zero

at org.zollty.framework.mvc.handler.support.AA.ccc(AA.java:25)

at org.zollty.framework.mvc.handler.support.AA.main(AA.java:60)

这样的错误信息,准确,简洁。

至于有人想看这个ExceptionWrapper的源码(几乎就是重新定义了java.lang.Throwable的大多数方法),等下一篇文章我再介绍吧。记住我的git地址,第一时间获取更新信息:

https://github.com/zollty

Java异常处理设计(一)的更多相关文章

  1. Java异常处理设计(三)

    接着上一篇讲. 一个异常日志处理的例子: 抛出异常的地方为: try{ ... ...//省略N行 }catch( Exception e){ throw new RuntimeException ( ...

  2. Java异常处理设计(二)

    考虑对JDK的底层堆栈信息进行处理,一种是重写JDK的Throwable,另一种是在原错误堆栈信息上进行“二次加工”.目前这两种方式我都实现了,效果非常好. 这篇文章主要记录对错误堆栈进行“二次加工” ...

  3. Java异常处理和设计

    在程序设计中,进行异常处理是非常关键和重要的一部分.一个程序的异常处理框架的好坏直接影响到整个项目的代码质量以及后期维护成本和难度.试想一下,如果一个项目从头到尾没有考虑过异常处理,当程序出错从哪里寻 ...

  4. Java异常处理和设计【转】

    Java异常处理和设计 在程序设计中,进行异常处理是非常关键和重要的一部分.一个程序的异常处理框架的好坏直接影响到整个项目的代码质量以及后期维护成本和难度.试想一下,如果一个项目从头到尾没有考虑过异常 ...

  5. java异常处理的设计

    有一句这样话:一个衡量Java设计师水平和开发团队纪律性的好方法就是读读他们应用程序里的异常处理代码. 本文主要讨论开发Java程序时,如何设计异常处理的代码,如何时抛异常,捕获到了怎么处理,而不是讲 ...

  6. 札记:Java异常处理

    异常概述 程序在运行中总会面临一些"意外"情况,良好的代码需要对它们进行预防和处理.大致来说,这些意外情况分三类: 交互输入 用户以非预期的方式使用程序,比如非法输入,不正当的操作 ...

  7. JAVA 异常处理机制

    主要讲述几点: 一.异常的简介 二.异常处理流程 三.运行时异常和非运行时异常 四.throws和throw关键字 一.异常简介 异常处理是在程序运行之中出现的情况,例如除数为零.异常类(Except ...

  8. 深入理解java异常处理机制

       异常指不期而至的各种状况,如:文件找不到.网络连接失败.非法参数等.异常是一个事件,它发生在程序运行期间,干扰了正常的指令流程.Java通 过API中Throwable类的众多子类描述各种不同的 ...

  9. Java提高篇——Java 异常处理

    异常的概念 异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的. 比如说,你的代码少了一个分号,那么运行出来结果是提示是错误java.lang.Error:如果你用Syst ...

随机推荐

  1. Tomcat架构解析(六)-----BIO、NIO、NIO2、APR

    对于应用服务器来说,性能是非常重要的,基本可以说决定着这款应用服务器的未来.通常从软件角度来说,应用服务器性能包括如下几个方面: 1.请求处理的并发程度,当前主流服务器均采用异步的方式处理客户端的请求 ...

  2. 使用 docker compose 安装 tidb

    目标 : 单机上通过 Docker Compose 快速一键部署一套 TiDB 测试集群 前提条件: 1.centos版本在7.3 以上 2.安装git 3.安装docker Docker versi ...

  3. 第1章 Python数据模型

    #<流畅的Python>读书笔记 # 第一部分 序幕 # 第1章 Python数据模型 # 魔术方法(magic method)是特殊方法的昵称.于是乎,特殊方法也叫双下方法(dunder ...

  4. java常用设计模式六:适配器模式

    一.定义 适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作.比如以下的场景: 用手机充电为例,有一个手机的插孔是TypeC口,现在只 ...

  5. hadoop配置分区

    1.运行MR,得出HDFS路径下数据 2.创建 Hive 表 映射 HDFS下的数据 3.为数据创建分区,在hive下执行 source 分区表: TIPS:结果集的时间,必须在分区范围内: 可以理解 ...

  6. Oracle修改数据库的日期

    ---Oracle数据库更新时间字段数据时的sql语句---格式化时间插入 update t_invite_activityinfo set endtime=to_date('2019-10-30 1 ...

  7. 新建maven遇到的错误

    新建一个maven,遇到错误如下: Description Resource Path Location Type Dynamic Web Module 3.0 requires Java 这时候,只 ...

  8. 虚拟机CentOs的安装及大数据的环境搭建

      大数据问题汇总     1.安装问题        1.安装步骤,详见文档<centos虚拟机安装指南>        2.vi编辑器使用问题,详见文档<linux常用命令.pd ...

  9. HDU 1003 MAXSUM(最大子序列和)

    Description Given a sequence a[1],a[2],a[3]......a[n], your job is to calculate the max sum of a sub ...

  10. 手机开发-IOS

    IOS 语言.Object-C,苹果公司收购的语言,专用于IOS开发,是C语言的超集,面向对象的. 开发环境.一是XCode,是苹果的IDE,提供了控件.二是Instruments,测试性能用,收集显 ...