一、分析
在finally中处理return返回值,代码上看上去很完美,都符合逻辑,但是执行起来就会产生逻辑错误,最重要的一点是finally是用来做异常处理的收尾处理的,一旦加上return语句,就会让程序的复杂程度陡然提升,而且会在一些隐蔽性非常高的错误。
doStuff(-1)的值是-1,doStuff(100)的值也是-1,调用doStuff方法永远都会抛出异常。原因就是我们在finally代码块中加入了return语句,而回导致这两个问题:
1.覆盖了try代码块中的return返回值
当执行doStuff(-1)时,doStuff方法产生了DataFormatException异常,catch块在捕捉此异常后直接抛出,之后代码块执行到finally代码块,就会重置返回值,结果就是-1了,也就出现了先返回,在执行finally,在重置返回值的情况。
2.屏蔽异常
为什么明明把异常throw出去了,但main方法捕捉不到呢?这是因为异常线程在监视到有异常发生时,就会登记当前的异常类型为DataFormatException,但是当执行器执行finally代码块时,则会重新为doStuff方法赋值,也就是告诉调用者“该方法执行正确,没有产生异常,返回值是1”,于是乎,异常就神奇的消失了。
三、建议
不要在finally代码块出现return语句。
在finally中处理return返回值,代码上看上去很完美,都符合逻辑,但是执行起来就会产生逻辑错误,最重要的一点是finally是用来做异常处理的收尾处理的,一旦加上return语句,就会让程序的复杂程度陡然提升,而且会在一些隐蔽性非常高的错误。
与return语句相似,System.exit(0)或Runtime.getRuntime().exit(0)出现在异常代码块中也会产生非常多的错误假象。
二、场景
如代码如下:
public static void main(String[] args){
try{
doStuff(-1);
doStuff(100);
}catch(Exception e){
System.out.println("这里是永远都不会到达的");
}
}
//该方法抛出受检异常
public static int doStuff(int _p)throws Exception{
try{
if(_p < 0){
throw new DataFormatException("数据格式错误");
}else{
return _p;
}
}catch(Exception e){
//异常处理
throw e;
}finally{
return -1;
}
}
doStuff(-1)的值是-1,doStuff(100)的值也是-1,调用doStuff方法永远都会抛出异常。原因就是我们在finally代码块中加入了return语句,而回导致这两个问题:
1.覆盖了try代码块中的return返回值
当执行doStuff(-1)时,doStuff方法产生了DataFormatException异常,catch块在捕捉此异常后直接抛出,之后代码块执行到finally代码块,就会重置返回值,结果就是-1了,也就出现了先返回,在执行finally,在重置返回值的情况。
2.屏蔽异常
为什么明明把异常throw出去了,但main方法捕捉不到呢?这是因为异常线程在监视到有异常发生时,就会登记当前的异常类型为DataFormatException,但是当执行器执行finally代码块时,则会重新为doStuff方法赋值,也就是告诉调用者“该方法执行正确,没有产生异常,返回值是1”,于是乎,异常就神奇的消失了。
三、建议
不要在finally代码块出现return语句。