码工魄之JAVA异常处理 ^^^^^^^^^^^^^^^^^^^^^^ - 作者:臭豆腐[trydofor.com] - 日期:2009-12-16 - 授权:署名-非商业-保持一致 1.0 协议 - 声明:拷贝、分发、呈现和表演本作品,请保留以上全部信息。 0. 文档目录 ^^^^^^^^^^^ [[<=$INDEX]] 1. 异常作用 ^^^^^^^^^^^ 如果把程序比作一棵树,那么,根系是需求,正常逻辑是主干,异常处理就是枝叶。 枝叶健康得当便有更多机会捕捉阳光雨露,歪斜则易断枝,过大还招风呢 ^_^) 因此,异常处理的好坏,恰当与否,都反映和影响着程序的健康状态与生命力。 JAVA异常有三大类,关系如下:[ST] ........................................ java.lang.Object |-java.lang.Throwable |-java.lang.Error |-java.lang.Exception |-java.lang.RuntimeException ........................................ 第一类,是受检异常(checked exception)。 用来提示用户注意和适当的处理,是可预期的和修复的。 第二类,是错误(error),由java.lang.Error及其子类组成。 用来表示程序外部错误,一般不可预期和修复,比如硬件资源。 第三类,是运行时异常(runtime exception), 由java.lang.RuntimeException及其子类组成。 用来表示程序内部错误,一般不可预期和修复,比如程序bug。 2. 大师总结 ^^^^^^^^^^^ “Effective Java 第2版”的第九章,专门讲了异常,提到的经验有。[EJ] * 第57条:只针对异常的情况才使用异常。 * 第58条:对可恢复的情况使用受检异常,对编程错误使用运行时异常。 * 第59条:避免不必要地使用受检异常。 * 第60条:优先使用标准的异常。 * 第61条:抛出与抽象相对应的异常。 * 第62条:每个方法抛出的异常都要有文档。 * 第63条:在细节消息中包含能捕捉的失败的信息。 * 第64条:努力使失败保持原子性。 * 第65条:不要忽略异常。 其中, 第60条指示我们,使用以下常用异常: * IllegalArgumentException 参数不合适 * IllegalStateException 对象状态不合适 * NullPointerException 禁止null * IndexOutOfBoundsException 下标越界 * ConcurrentModificationException 并发修改 * UnsupportedOperationException 操作为实现 第61条提到了异常链(exception chaining),经常用到的方法有: * Throwable getCause() * Throwable initCause(Throwable) * Throwable(String, Throwable) * Throwable(Throwable) * Throwable getStackTrace() * Throwable setStackTrace(StackTraceElement[]) 3. 常用异常 ^^^^^^^^^^^ 对jdk1.6.0_16和spring-framework-3.0.0.RELEASE-with-docs.zip的源代码中使用 的异常进行了粗略的统计和排序,以下是过程和结果,也反映了第60条经验。 [[java6数据=>./data/java6.zip]][[spring3数据=>./data/spring3.zip]] ========================= tty: 异常的统计过程 ========================= pwd >/home/trydofor/java mkdir java6-src/ cd java6-src/ unzip ../src.zip cd .. unzip spring-framework-3.0.0.RELEASE-with-docs.zip mv spring3-src/spring-framework-3.0.0.RELEASE spring3-src ll >drwxrwxr-x 2 trydofor trydofor 4096 Dec 19 09:22 java6-src >drwxrwxr-x 2 trydofor trydofor 4096 Dec 19 09:23 spring3-src >-rw-rw-r-- 1 trydofor trydofor 46699488 Dec 18 09:07 > spring-framework-3.0.0.RELEASE-with-docs.zip >-rw-rw-r-- 1 trydofor trydofor 19641221 Jul 31 16:30 src.zip find java6-src -name '*.java' |wc -l >7196 find spring3-src/projects/ -name '*.java'|wc -l >4093 #spring3-src/projects/org.springframework.expression/src/main/java/org/ #springframework/expression/common/TemplateAwareExpressionParser.java #这个类是Mac下编写的,需要把 \r换成 \n 才能正确处理,否则整个文件当做一行处理。 find java6-src -name '*.java' |xargs cat | tr '\r' '\n'| grep '[ \t\n]*throw[ \t\n]\+new' > java6.thrown.txt find spring3-src/projects -name '*.java'|xargs cat | tr '\r' '\n'| grep '[ \t\n]*throw[ \t\n]\+new' > spring3.thrown.txt wc -l *.txt > 10959 java6.thrown.txt > 2994 spring3.thrown.txt > 13953 total sed -n 's/.*throw[ \t]\+new[ \t]\+\([^(]\+\).\+/\1/p' java6.thrown.txt | sort |uniq -c | sort -nr >java6.exception.txt sed -n 's/.*throw[ \t]\+new[ \t]\+\([^(]\+\).\+/\1/p' spring3.thrown.txt | sort |uniq -c | sort -nr >spring3.exception.txt head java6.exception.txt > 2153 IllegalArgumentException > 795 NullPointerException > 438 RuntimeException > 295 UnsupportedOperationException > 291 DOMException > 280 IllegalStateException > 245 IOException > 219 IndexOutOfBoundsException > 185 ReadOnlyBufferException > 161 InternalError head spring3.exception.txt > 574 IllegalStateException > 561 IllegalArgumentException > 217 UnsupportedOperationException > 128 RuntimeException > 66 InvalidResultSetAccessException > 62 SpelEvaluationException > 56 OperationNotSupportedException > 55 TransactionSystemException > 52 InvalidDataAccessApiUsageException > 47 ServletException ========================================================================= 4. 低级习惯 ^^^^^^^^^^^ 1) 作为流程控制。违法异常设计初衷。 2) 私吞异常。包括空catch块或printStackTrace等伪处理。异常,要么处理好,要么不处理。 3) 异常覆盖。catch或finally块内引发异常,覆盖源头问题,信息丢失。 ================= java: 异常转换与防覆盖 ================= boolean succeed = false; List r = null; S2AttributeReportDao dao = null; try{ dao = new S2AttributeReportDao(); r = dao.getNewNameReportCandidates(jicAccountDate); succeed = true; }catch(DaoException e){ throw new ServiceException(e); }finally{ if(dao != null){ try{ dao.dispose(); }catch(DaoException de){ if(succeed){ throw new ServiceException(de); } } } } return r==null?new ArrayList():r; ========================================================== 5. 参考资料 ^^^^^^^^^^^ * ST [[Sun的Java指南=>http://java.sun.com/docs/books/tutorial/essential/exceptions/index.html]] * EJ Effective Java 第2版(ISBN 978-7-111-25583-3,机械工业出版社)