码工魄之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,机械工业出版社)