关于try catch finally的问题

《java编程思想》中曾指出异常丢失问题

public class Demo1 {
    
    void f1() throws MyException1{
        throw new MyException1();
    }
    void f2() throws MyException2{
        throw new MyException2();
    }
    
    public static void main(String[] args) {
        Demo1 d = new Demo1();
        try{
            try {
                d.f1();
            }finally {
                d.f2();
            }
        }catch (Exception e){
            System.out.println(e);
        }
 
    }
 
}
 
class MyException1 extends Exception{
    @Override
    public String toString() {
        return "MyException1...";
    }
}
class MyException2 extends Exception{
    @Override
    public String toString() {
        return "MyException2...";
    }
}
输出结果为:
MyException2...

MyException1未打印。

原因可以归结为:调用某一个抛出异常的方法,原则上必须catch该异常,但是可以把该异常处理块放在一个更大的try块里面,由外部的try块来处理异常。这样字块finally中抛出的异常会“覆盖”之前的异常,从而导致前一个异常丢失。下面可以简单证实“异常覆盖”问题:

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        try {
            int a = 1/0;
        }finally {
            String s = null;
            s.length();
        }
        
    }
输出结果为:

Exception in thread "main" java.lang.NullPointerException
at huli.Demo.main(Demo.java:13)

可见只抛出了空指针异常,而 / by zero 异常丢失了,或者说被finally字句的异常覆盖了。

另外,finally中的return语句也可能导致异常丢失:

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        try {
            int a = 1/0;
            Class.forName("abcd");
        } catch (ClassNotFoundException e) {
            System.out.println("hehe");        
        }finally {
            System.out.println("haha");
            return;
        }
        
    }
输出为:
haha

同样导致了异常丢失问题。

或许有效的建议:

1)使用try...finally块时要格外小心,如果可以的话,尽量使用完整的try...catch...finally

2)尽量不要在finally块中写return

 


结论:
1、不管有木有出现异常,finally块中代码都会执行;
2、当try和catch中有return时,finally仍然会执行;
3、finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的;
4、finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。
举例:
情况1:try{} catch(){}finally{} return;
            显然程序按顺序执行。


情况2:try{ return; }catch(){} finally{} return;
          程序执行try块中return之前(包括return语句中的表达式运算)代码;
         再执行finally块,最后执行try中return;
         finally块之后的语句return,因为程序在try中已经return所以不再执行。


情况3:try{ } catch(){return;} finally{} return;
         程序先执行try,如果遇到异常执行catch块,
         有异常:则执行catch中return之前(包括return语句中的表达式运算)代码,再执行finally语句中全部代码,
                     最后执行catch块中return. finally之后也就是4处的代码不再执行。
         无异常:执行完try再finally再return.


情况4:try{ return; }catch(){} finally{return;}
          程序执行try块中return之前(包括return语句中的表达式运算)代码;
          再执行finally块,因为finally块中有return所以提前退出。


情况5:try{} catch(){return;}finally{return;}
          程序执行catch块中return之前(包括return语句中的表达式运算)代码;
          再执行finally块,因为finally块中有return所以提前退出。


情况6:try{ return;}catch(){return;} finally{return;}
          程序执行try块中return之前(包括return语句中的表达式运算)代码;
          有异常:执行catch块中return之前(包括return语句中的表达式运算)代码;
                       则再执行finally块,因为finally块中有return所以提前退出。
          无异常:则再执行finally块,因为finally块中有return所以提前退出。


最终结论:任何执行try 或者catch中的return语句之前,都会先执行finally语句,如果finally存在的话。
                  如果finally中有return语句,那么程序就return了,所以finally中的return是一定会被return的,
                  编译器把finally中的return实现为一个warning。

public class FinallyTest  
{
	public static void main(String[] args) {
		 
		System.out.println(new FinallyTest().test());;
	}

	static int test()
	{
		int x = 1;
		try
		{
			x++;
			return x;
		}
		finally
		{
			++x;
		}
	}
}
结果是2。
在try语句中,在执行return语句时,要返回的结果已经准备好了,就在此时,程序转到finally执行了。
在转去之前,try中先把要返回的结果存放到不同于x的局部变量中去,执行完finally之后,在从中取出返回结果,
因此,即使finally中对变量x进行了改变,但是不会影响返回结果。
它应该使用栈保存返回值。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值