- 浏览: 1637806 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (405)
- C/C++ (16)
- Linux (60)
- Algorithm (41)
- ACM (8)
- Ruby (39)
- Ruby on Rails (6)
- FP (2)
- Java SE (39)
- Java EE (6)
- Spring (11)
- Hibernate (1)
- Struts (1)
- Ajax (5)
- php (2)
- Data/Web Mining (20)
- Search Engine (19)
- NLP (2)
- Machine Learning (23)
- R (0)
- Database (10)
- Data Structure (6)
- Design Pattern (16)
- Hadoop (2)
- Browser (0)
- Firefox plugin/XPCOM (8)
- Eclise development (5)
- Architecture (1)
- Server (1)
- Cache (6)
- Code Generation (3)
- Open Source Tool (5)
- Develope Tools (5)
- 读书笔记 (7)
- 备忘 (4)
- 情感 (4)
- Others (20)
- python (0)
最新评论
-
532870393:
请问下,这本书是基于Hadoop1还是Hadoop2?
Hadoop in Action简单笔记(一) -
dongbiying:
不懂呀。。
十大常用数据结构 -
bing_it:
...
使用Spring MVC HandlerExceptionResolver处理异常 -
一别梦心:
按照上面的执行,文件确实是更新了,但是还是找不到kernel, ...
virtualbox 4.08安装虚机Ubuntu11.04增强功能失败解决方法 -
dsjt:
楼主spring 什么版本,我的3.1 ,xml中配置 < ...
使用Spring MVC HandlerExceptionResolver处理异常
异常处理是写一个健壮的程序的非常重要的但经常被忽视的方面。如何去抛出、捕获和处理异常有不同的
方式,并不是每种方式都很有效。
一、设计异常层次:
好处:
1.声明捕获一个异常,可以自动的捕获其子类的异常。
2.可以进行多个catch,对不同的异常进行不同的处理,比如FileNotFoundException和IOException.
3.方法中声明抛throws子句中的异常,函数体可以抛出异常的子类型,子类覆写的类也可以声明抛出异常的子类型。
当设计异常层次的API或者应用时,最好设计一个这类API或者应用异常的基类。比如一个持久化的应用,定义一个
基类异常PersistenceException,然后根据不同的异常定义出ConnectionOpenException, QueryException,
UpdateException, CommitException, and ConnectionCloseException.
二、Checked VS Unchecked Exceptions
大多的Java书籍的建议都是:如果异常可以恢复,那么使用checked,严重的不可恢复的错误使用unchecked异常。
优缺点:
Checked Exceptions
优点:
编译的时候强制处理异常,可以强迫对异常进行恰当的处理,
缺点:
1.Checked Exception根据调用链向上传播异常,上层的函数被迫处理或者抛出大量的异常。
2.Checked Exception成为方法/接口的一部分,移除、添加非常困难。
Unchecked Exceptions
优点:
1.不强制抛出、处理,当仍然可以和checked一样处理,代码更简洁、容易阅读。
2.不会将异常称为方法/接口的一部分,方便API的演化。
2.如果使用更多的Unchecked Exceptions可以养成处理异常的习惯,而不仅仅处理Checked Exception。
缺点:
容易忘记处理,因为没有编译的强制的check。
我们通常会在上层的、集中的几个类里面处理异常,而不是是分散在各处来处理异常,这样Unchecked Exceptions
非常适合,因为有时由于API异常声明的限制,Checked Exception强迫我们必须捕获处理。这种方式更容易一致
的处理异常,代码更容易维护,所以现在越来越推荐这样Unchecked方式。
三、包装Exception
为什么要包装?原因:
1、异常声明会在调用链上向上聚集,如果不包装异常可能导致上层调用的函数声明太多不同的异常。
2、不想将下层组件的细节暴露给上层,比如你定义了抽象的数据访问层,那么你不想让其他的应用知道数据访问层的细节,
比如你不应该向上层抛出SQLException和FileNotFoundException,而可能包装出一个DAOException,然后定义出
异常层次结构。
四、安全的处理异常:
如果处理不当,在catch和finally中声明的异常可能被隐藏掉:
如果myFile.txt文件不存在,可能导致input为null,而在finally没有判断input != null就close了,这会导致NullException,
并且抛出的WrapperException在异常堆栈中被冲掉。
虽然加了input != null,但是下面代码仍然有问题:
如果关闭出现了异常,那么第一个catch抛出的异常可能被冲掉。
五、异常增强(Exception Enrichment):
包装异常可能导致以下问题:
1、异常堆栈可能会变得很深,但是我们经常只需要异常跟踪的根。
2、异常信息散布在整个的异常堆栈中,这样可能导致很难判断问题出在哪里。
六、可插拔的异常处理器:
用户处理去处理、log、增强异常,可以通过把异常处理代理给可插拔的异常处理器可以让用户自定义异常处理。
比如我们定义个异常处理器接口:
我们在以下代码中使用它:
异常处理器可以决定是处理、忽略、log、包装还是重新抛出。
可以实现一些标准的异常处理器:
七、Log异常:
如果我们的应用程序发生了业务错误,我们应该log下来,以便为排错提供信息。那么代码的什么地方应该log异常呢?
有以下几种:
1、Bottom Level Logging
当异常发生时log
缺点:
1)log需要分布在任何发生异常或者第三方库抛出异常的地方,需要非常多的分散的log,难于维护和管理。
2)一个公用的组建可能不知道足够的详细错误信息查找错误的原因。
2、Mid Level Logging
在调用的中间的某个地方,这时候有了足够的信息可以log下来。
缺点:仍然需要非常多分散在各处的log,难于维护和管理
3、Top Level Logging
log集中在少数的的Top Level的调用链上。
可以允许在单个集中的地方捕获并log异常,容易维护。
缺点:
Top Level Logging不知道底层组件到底发生了什么错误,Mid Level使用底层组建到底要做什么。
可以通过增强异常的方式来解决这个问题。
比较推荐使用Top Level Logging,因为非常容易log和维护。
八、验证
1、尽快的抛出异常:
比如以下操作
check if user already exists
validate user
validate address
insert user
insert address
而不是
check if user already exists
validate user
insert user
validate address
insert address
2、抛出异常还是返回false
如果想交互性的一个一个的让用户纠正错误,那么最好抛出异常。
如果需要批量的发现了一堆错误,然后让用户修正,那么return false
九、使用异常处理模板方法:
异常处理很多是样板式的代码,模板方法可以解决这个问题:
比如:
可以使用模板方法,Spring大量使用该方法来处理事务等操作:
参考:
http://tutorials.jenkov.com/java-exception-handling/index.html
http://onjava.com/pub/a/onjava/2003/11/19/exceptions.html
方式,并不是每种方式都很有效。
一、设计异常层次:
好处:
1.声明捕获一个异常,可以自动的捕获其子类的异常。
2.可以进行多个catch,对不同的异常进行不同的处理,比如FileNotFoundException和IOException.
3.方法中声明抛throws子句中的异常,函数体可以抛出异常的子类型,子类覆写的类也可以声明抛出异常的子类型。
当设计异常层次的API或者应用时,最好设计一个这类API或者应用异常的基类。比如一个持久化的应用,定义一个
基类异常PersistenceException,然后根据不同的异常定义出ConnectionOpenException, QueryException,
UpdateException, CommitException, and ConnectionCloseException.
二、Checked VS Unchecked Exceptions
大多的Java书籍的建议都是:如果异常可以恢复,那么使用checked,严重的不可恢复的错误使用unchecked异常。
优缺点:
Checked Exceptions
优点:
编译的时候强制处理异常,可以强迫对异常进行恰当的处理,
缺点:
1.Checked Exception根据调用链向上传播异常,上层的函数被迫处理或者抛出大量的异常。
2.Checked Exception成为方法/接口的一部分,移除、添加非常困难。
Unchecked Exceptions
优点:
1.不强制抛出、处理,当仍然可以和checked一样处理,代码更简洁、容易阅读。
2.不会将异常称为方法/接口的一部分,方便API的演化。
2.如果使用更多的Unchecked Exceptions可以养成处理异常的习惯,而不仅仅处理Checked Exception。
缺点:
容易忘记处理,因为没有编译的强制的check。
我们通常会在上层的、集中的几个类里面处理异常,而不是是分散在各处来处理异常,这样Unchecked Exceptions
非常适合,因为有时由于API异常声明的限制,Checked Exception强迫我们必须捕获处理。这种方式更容易一致
的处理异常,代码更容易维护,所以现在越来越推荐这样Unchecked方式。
三、包装Exception
为什么要包装?原因:
1、异常声明会在调用链上向上聚集,如果不包装异常可能导致上层调用的函数声明太多不同的异常。
2、不想将下层组件的细节暴露给上层,比如你定义了抽象的数据访问层,那么你不想让其他的应用知道数据访问层的细节,
比如你不应该向上层抛出SQLException和FileNotFoundException,而可能包装出一个DAOException,然后定义出
异常层次结构。
四、安全的处理异常:
如果处理不当,在catch和finally中声明的异常可能被隐藏掉:
InputStream input = null; try{ input = new FileInputStream("myFile.txt"); //do something with the stream } catch(IOException e){ throw new WrapperException(e); } finally { try{ input.close(); } catch(IOException e){ throw new WrapperException(e); } }
如果myFile.txt文件不存在,可能导致input为null,而在finally没有判断input != null就close了,这会导致NullException,
并且抛出的WrapperException在异常堆栈中被冲掉。
虽然加了input != null,但是下面代码仍然有问题:
InputStream input = null; try{ input = new FileInputStream("myFile.txt"); //do something with the stream } catch(IOException e){ //first catch block throw new WrapperException(e); } finally { try{ if(input != null) input.close(); } catch(IOException e){ //second catch block throw new WrapperException(e); } }
如果关闭出现了异常,那么第一个catch抛出的异常可能被冲掉。
五、异常增强(Exception Enrichment):
包装异常可能导致以下问题:
1、异常堆栈可能会变得很深,但是我们经常只需要异常跟踪的根。
2、异常信息散布在整个的异常堆栈中,这样可能导致很难判断问题出在哪里。
public void method3() throws EnrichableException{ try{ method1(); } catch(EnrichableException e){ e.addInfo("METHOD3", "ERROR1", "An error occurred when trying to ..."); throw e; } } public void method2() throws EnrichableException{ try{ method1(); } catch(EnrichableException e){ e.addInfo("METHOD2", "ERROR1", "An error occurred when trying to ..."); throw e; } } public void method1() throws EnrichableException { if(...) throw new EnrichableException( "METHOD1", "ERROR1", "Original error message"); }
import java.util.ArrayList; import java.util.List; public class EnrichableException extends RuntimeException { public static final long serialVersionUID = -1; protected List<InfoItem> infoItems = new ArrayList<InfoItem>(); protected class InfoItem{ public String errorContext = null; public String errorCode = null; public String errorText = null; public InfoItem(String contextCode, String errorCode, String errorText){ this.errorContext = contextCode; this.errorCode = errorCode; this.errorText = errorText; } } public EnrichableException(String errorContext, String errorCode, String errorMessage){ addInfo(errorContext, errorCode, errorMessage); } public EnrichableException(String errorContext, String errorCode, String errorMessage, Throwable cause){ super(cause); addInfo(errorContext, errorCode, errorMessage); } public EnrichableException addInfo( String errorContext, String errorCode, String errorText){ this.infoItems.add( new InfoItem(errorContext, errorCode, errorText)); return this; } public String getCode(){ StringBuilder builder = new StringBuilder(); for(int i = this.infoItems.size()-1 ; i >=0; i--){ InfoItem info = this.infoItems.get(i); builder.append('['); builder.append(info.errorContext); builder.append(':'); builder.append(info.errorCode); builder.append(']'); } return builder.toString(); } public String toString(){ StringBuilder builder = new StringBuilder(); builder.append(getCode()); builder.append('\n'); //append additional context information. for(int i = this.infoItems.size()-1 ; i >=0; i--){ InfoItem info = this.infoItems.get(i); builder.append('['); builder.append(info.errorContext); builder.append(':'); builder.append(info.errorCode); builder.append(']'); builder.append(info.errorText); if(i>0) builder.append('\n'); } //append root causes and text from this exception first. if(getMessage() != null) { builder.append('\n'); if(getCause() == null){ builder.append(getMessage()); } else if(!getMessage().equals(getCause().toString())){ builder.append(getMessage()); } } appendException(builder, getCause()); return builder.toString(); } private void appendException( StringBuilder builder, Throwable throwable){ if(throwable == null) return; appendException(builder, throwable.getCause()); builder.append(throwable.toString()); builder.append('\n'); }
六、可插拔的异常处理器:
用户处理去处理、log、增强异常,可以通过把异常处理代理给可插拔的异常处理器可以让用户自定义异常处理。
比如我们定义个异常处理器接口:
public interface ExceptionHandler { public void handle(Exception e, String errorMessage); }
我们在以下代码中使用它:
public class Component{ protected ExceptionHandler exceptionHandler = null; public void setExceptionHandler(ExceptionHandler handler){ this.exceptionHandler = handler; } public void processFile(String fileName){ FileInputStream input = null; try{ input = new FileInputStream(fileName); processStream(input); } catch (IOException e){ this.exceptionHandler.handle(e, "error processing file: " + fileName); } } protected void processStream(InputStream input) throws IOException{ //do something with the stream. } }
异常处理器可以决定是处理、忽略、log、包装还是重新抛出。
可以实现一些标准的异常处理器:
public class IgnoringHandler implements ExceptionHandler{ public void handle(Exception e, String message) { //do nothing, just ignore the exception } } public class WrappingHandler implements ExceptionHandler{ public void handle(Exception e, String message){ throw new RuntimeException(message, e); } } public class CollectingHandler implements ExceptionHandler{ List exceptions = new ArrayList(); public List getExceptions(){ return this.exceptions; } public void handle(Exception e, String message){ this.exceptions.add(e); //message is ignored here, but could have been //collected too. } }
七、Log异常:
如果我们的应用程序发生了业务错误,我们应该log下来,以便为排错提供信息。那么代码的什么地方应该log异常呢?
有以下几种:
1、Bottom Level Logging
当异常发生时log
缺点:
1)log需要分布在任何发生异常或者第三方库抛出异常的地方,需要非常多的分散的log,难于维护和管理。
2)一个公用的组建可能不知道足够的详细错误信息查找错误的原因。
2、Mid Level Logging
在调用的中间的某个地方,这时候有了足够的信息可以log下来。
缺点:仍然需要非常多分散在各处的log,难于维护和管理
3、Top Level Logging
log集中在少数的的Top Level的调用链上。
可以允许在单个集中的地方捕获并log异常,容易维护。
缺点:
Top Level Logging不知道底层组件到底发生了什么错误,Mid Level使用底层组建到底要做什么。
可以通过增强异常的方式来解决这个问题。
比较推荐使用Top Level Logging,因为非常容易log和维护。
八、验证
1、尽快的抛出异常:
比如以下操作
引用
check if user already exists
validate user
validate address
insert user
insert address
而不是
引用
check if user already exists
validate user
insert user
validate address
insert address
2、抛出异常还是返回false
如果想交互性的一个一个的让用户纠正错误,那么最好抛出异常。
如果需要批量的发现了一堆错误,然后让用户修正,那么return false
九、使用异常处理模板方法:
异常处理很多是样板式的代码,模板方法可以解决这个问题:
比如:
Input input = null; IOException processException = null; try{ input = new FileInputStream(fileName); //...process input stream... } catch (IOException e) { processException = e; } finally { if(input != null){ try { input.close(); } catch(IOException e){ if(processException != null){ throw new MyException(processException, e, "Error message..." + fileName); } else { throw new MyException(e, "Error closing InputStream for file " + fileName; } } } if(processException != null){ throw new MyException(processException, "Error processing InputStream for file " + fileName; }
可以使用模板方法,Spring大量使用该方法来处理事务等操作:
public abstract class InputStreamProcessingTemplate { public void process(String fileName){ IOException processException = null; InputStream input = null; try{ input = new FileInputStream(fileName); doProcess(input); } catch (IOException e) { processException = e; } finally { if(input != null){ try { input.close(); } catch(IOException e){ if(processException != null){ throw new MyException(processException, e, "Error message..." + fileName); } else { throw new MyException(e, "Error closing InputStream for file " + fileName; } } } if(processException != null){ throw new MyException(processException, "Error processing InputStream for file " + fileName; } } //override this method in a subclass, to process the stream. public abstract void doProcess(InputStream input) throws IOException; } new InputStreamProcessingTemplate(){ public void doProcess(InputStream input) throws IOException{ int inChar = input.read(); while(inChar !- -1){ //do something with the chars... } } }.process("someFile.txt");
参考:
http://tutorials.jenkov.com/java-exception-handling/index.html
http://onjava.com/pub/a/onjava/2003/11/19/exceptions.html
发表评论
-
Builder模式遇到继承
2013-10-13 13:48 0interface Self<T extends ... -
Builder模式遇到集成
2013-10-13 13:47 0package com.qunar.qss.business. ... -
JVM调优Step by Step
2012-02-02 17:38 0现代的JVM能够适应于各种应用和领域,每个应用和领域的使用 ... -
commons-lang StringUtils#split的坑
2011-12-31 10:11 3114今天用StringUtils#split,陷入了前两个坑。需求 ... -
使用scala.sys.process包和系统交互
2011-07-19 00:00 6441在Java中我们可以使用Runtime.getRuntime( ... -
HttpClient Json请求工具
2011-05-05 18:32 17805发送Json请求,结果返回Json. public sta ... -
利用Java反射实现通用的Excel报表
2011-04-12 16:00 1983最近有很多客户报表需要提供客户下载,需要生成一个Excel的格 ... -
Java序列化注意一些点
2011-03-12 21:04 18151.序列化ID的问题: 标示了版本号,版本号一致才能反序列化成 ... -
Java动态代理
2010-09-24 00:34 4402Java提供了动态代理,可以完成AOP和装饰模式的功能,主要的 ... -
Java Timestamp是和ExtJS的timestamp不兼容
2010-08-09 20:33 3323Timestamp纳秒级别的,ExtJS的timestamp使 ... -
XML DocumentBuilder#parse(String str)
2010-07-06 15:55 3850DocumentBuilderFactory dbf = ... -
[备忘]String#split/substring的子串会共享原来大的String
2010-03-29 17:18 1452如果每次需要大字符串中的很小的一个字串,可能会引起内存中大量的 ... -
runtime.exec()执行进程block死锁问题
2010-01-18 21:39 5234最近在java代码中使用runtime.exec执行rsync ... -
URL中文问题
2010-01-08 14:46 10476最近使用HttpClient,和Java的java.net.U ... -
A TaskExecutor Impl
2009-12-07 11:33 1584import java.util.ArrayList; im ... -
使用XStream把Java对象XML/JSON格式的序列化和反序列化
2009-05-05 11:37 6191试了一下Thoughtworks的XStream,以测试驱动和 ... -
从《编程的未来》这篇文章想到C++和Java语言的爽与不爽
2009-05-01 23:44 3937从编程的未来这篇文 ... -
《Effetive Java》读书笔记二
2009-02-23 14:23 1568第二章 所有对象共有的 ... -
《Effetive Java》读书笔记一
2009-02-19 11:36 2138《Effetive Java》和 《Effective C++ ... -
如何彻底杜绝别人使用你的类
2008-05-22 19:30 2321今天在eclipse源码中发 ...
相关推荐
深入理解java异常处理机制,很详细的,去了,你们的!
在所有 Win32 操作系统提供的机制中,使用最广泛的未公开的机制恐怕就要数结构化异常处理(structured exception handling,SEH)了。一提到结构化异常处理,可能就会令人想起 _try、_finally 和 _except 之类的词儿...
什么时间使用runtimeException,什么时间使用Exception,大家有没有被困扰到?经整理,JAVA异常处理框架,以及如何构造自己的异常体系,讲得比较详细,值得一看。
在Win32操作系统提供的所有功能中,使用最广泛而又没有公开的恐怕要数结构化异常处理(Structured Exception Handling,SEH) 了。现在Microsoft仍然没有提供这些源代码,它提供的是编译过的目标文件,而Borland则...
深入理解java异常(异常中的Error+异常中的Exception+检查异常+运行时异常+异常处理+throws关键字等)
本文从Java异常最基本的概念、语法开始讲述了Java异常处理的基本知识,分析了Java异常体系结构,对比Spring的异常处理框架,阐述了异常处理的基本原则。并且作者提出了自己处理一个大型应用系统异常的思想,并通过...
对java异常的工作过程进行详细解释,让初学者更好的掌握异常处理机制
异常处理是Java编程中重要的概念和技巧之一,也是面试中常见的考点。...通过阅读本文,您将能够深入了解Java异常处理的原理、使用方法以及异常处理的最佳实践。不论您是准备面试还是希望加强对Java异常处理的知识掌握
深入理解java异常处理机制Java开发Java经验技巧共19页.pdf.zip
探索Win32结构化异常处理流程,可用于高级Windows调试或破解
深入探究Symbian资源管理和异常处理机制,甘寿聪,,本文通过比较Symbian OS C 与标准C 在异常处理机制上的差异,分析了Symbian OS如何分配和管理资源,以应对因程序员忘记回收或者异常所可
对c++异常处理的深入剖析,C++语言程序设计课后答案(清华大学郑莉)
本文旨在探讨Java的\"异常机制\",分别介绍了\"异常类\"的组织形式、\"异常\"的处理过程、\"异常\"的处理方法及使用\"异常机制\"的需要注意的问题。
Python的深入学习和提高涉及到多个方面,包括异常机制、文件处理、模块使用、GUI编程以及游戏开发等。具体如下: 异常机制:是Python中用于处理程序运行时错误的一种机制。它通过try和except语句来实现,其中try块...
本篇文章主要介绍了java异常处理机制及应用,异常处理机制是Java语言的一大特色。从异常处理的机制、异常处理的方法、异常处理的原则等方面介绍Java语言的异常处理技术,有兴趣的可以了解一下。
每个示例都展示了不同的方面,涵盖了面向对象编程、继承和多态、接口和实现、异常处理、集合框架、文件操作、多线程、输入输出、Lambda表达式和数据库连接等关键主题。 以下是每个示例的简要介绍: 1. 类和对象:...
异常(Exception)是一种错误处理机制,用于在指定的错误发生时改变脚本的正常流程。 当异常被触发时,当前代码状态被保存,代码执行被切换到预定义的异常处理器函数(如果有) 根据情况,处理器也许会从保存的代码...
详细讲解异常的始末,深入了解异常和解决异常。 明确 1、异常的概念 2、异常的种类 3、如何捕获和处理异常 4、处理异常时的注意点有哪些 附带一张异常的结构图
主要给大家介绍了关于Python异常处理的哲学,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
我们需要明白的是异常的发生不是因为我们代码写错了,我们的代码是可以编译的,但是在运行时产生了一个错误,这个错误是一个异常情况,计算机不能处理这个异常情况,就产生了一个异常。 总结一下异常发生:1.不是...