总结一下常见异常处理情况。并建议处理如下:
捕获的异常一定要再次抛出
我们写的Form、Action不具备处理异常的能力或者说处理能力非常有限,异常信息层层上报是明智的选择。
Action中的public 函数都有throws子句,它的作用就是要把异常交给服务器。所以在catch 一个异常后马上抛出它,这样其他人便容易获得异常的类型及出处。
Form 或其他类中可能抛出异常的函数(特别是public类型 )一定要有throws子句标明异常的出处。
抛出的异常用BaseRunException包装一下。HighSoft包中的BaseRunException就是专门包装异常的,可以在异常信息里加入一些说明。
不要在异常块内retrun
你也许写过或者见过类似的代码:
try{
//someThing may throws Exceptions
return 1;
}catch(Exception e){
throw new BaserunException(**);
return 2;
}finally{
//**
retrun 3;
}
return 4
你能描述它是怎样工作的么?他最终返回什么?(如果你说返回 3 那么你就错了,因为它编译都通不过)。
进入finally区块的情形:
1. Try语句正常结束。
2. Try语句中执行了retrun、break、contine等被迫离开。
3. Try语句异常抛出并且catch语句处理完毕。
由此看出
1. finally里返回,意味你永远不可能正确的结束了。(finally以下的正常retrun都无效了)。
2. Catch里返回,意味着你不能再将异常抛出。(即,返回和抛出只能选其一)。
3. Try里返回,就是这些混乱逻辑的源泉。
有一段这样的代码,它主要想这样:执行一个sql语句,成功了返回1(try块内),出错了返回-1(catch块内);然后在action里得到返回值报告给用户。这代码无疑非常愚蠢:出了错我知道错了(-1)除此之外错在那里、那种类型一无所知;幸好它没有在finally里在返回一下,否则连是否出错都看不出来了。
正确的写法应当是这样:
public int function() throws BaseRunException {
int result;
try{
/*****/
result = ***;
}catch(**Exception e){
throws BaseRunException(***); //抛出即可
}finally{
/**/
}
retrun result;//正常的返回
}
你要坚信:函数内一旦发生异常,程序当立即转入异常处理,此时任何的返回都没有意义。
异常块不应置于循环内
现在我们已经很少这样写了:
for(**){
DBTool =null;
try{
/***/
tool.excute**(**);
}catch(Exception e){***}***
}
但这样的写法也还会有:
for(**) {
functionCyc();
}
functionCyc(){
DBTool =null;
try{
/***/
tool.excute**(**);
}catch(Exception e){**}***
}
其实,程序中真正造成危害的不是第一种----它只是带来了效率的问题:try-cach执行消耗的资源。第二种才是真正致命的。
1. 函数间的关联。即便是priavte/static促成了内联(inline)它还是会有虚拟机频繁调用的效率问题。(所以,循环内的函数要尽量的“小”,当然与清晰的语义相比“关联消耗”可不予考虑)。
2. Try-catch块资源消耗问题。与第一种情况相同。
3. Non-memery“大对象”的资源占用问题。采取第二种做法,不得不在每次循环内占用一个数据库连接----这显然比连接不关闭来的直接。一般来说数据库链接有限--------公司的orcal 8.17只能支持200个连接,for一下是不是很快就满了?!
如果不得不循环调用某一函数执行数据库的操作时,就应该这样写:
。。。。。。。。
DBTool tool = null;
Try{
For(*****){
*****
functionCyc(****,tool);
*****
}
}catch(Exception e){
***
}finally{
if(**)**;
}
private void functionCyc(****,tool) throws **Exception{
**********
tool.excute**(****);
********
}
异常的抛出不能随意
也许曾经尝试这么做:
if(***) throw new **Exception(**);///并不在catch块里。
那么现在应该马上把它注释掉。
“「异常处理」(exception handling)只用于处理异常情况,不要把它拿来用于流程控制贯穿你的程序”、 “这个代码可以运作但性能地下含义模糊而且难以维护” 《Practical Java》。
确实,我写过这样的程序,问题多多。
给异常块瘦瘦身
try-catch模块只对“非同寻常的情况”负责。
习惯性的朝try块里塞一大堆东西,比如接收传来的参数、构造查询的参数等等,把它拿到外面,它一样工作,并且程序更有效率更容易读。
与此同时,也要净化以下程序,无用的代码统统去掉,一句废话会让别人琢磨半天。
“工蜂函数”早早抛出异常
“工蜂函数”既是常常(多处)被调用的函数,如果它有异常处理或将来可能会有,就早早抛出个异常,让所有调用端处理以下。
反面的例子:highsoft.yxgl.common.util.OptPostUtil:getOperListBySpcRoles()
它有异常处理却没有再次抛出,于是大家调用的时候也没有对它包装进try/catch块里。由于被多次调用,再想重构已经很难。