Java异常处理中你不知道的事

      Java 中经常会用到异常处理。可是你真的了解try...catch...finally语句的执行过程吗?先来看看这段代码:

public class TestException {
	
	public static void main(String[] args) {
		
		TestException te = new TestException();
		int a = te.test();
		System.out.println("call block. a: " + a);
	}
	
	public int test()
	{
		int a = 1;
		try
		{	//【1】
			a = a + 1;	//a:2
			System.out.println("try block. a: " + a);
			
			//this will cause an exception
			int b = a / 0; 	//【2】
			return a;	//【3】	
		}
		catch (Exception e)
		{//【4】
			a = a + 2;	//a:4
			System.out.println("catch block. a: " + a);//【5】
			return a;	//【6】
		}
		finally
		{//【7】
			a = a + 3;	//a:7
			System.out.println("finally block. a: " + a);//【8】
			//return a;	//【9】
		}	
		//return a;
	}//eof:test()
}

      问题来了: main函数中得到的a值是多少?
      如果你很确信地说答案是:4,那么你可以不用再在这篇文章上浪费时间了,它所说的东西你应该已经掌握了,去其他地方转转吧。但如果你认为答案是7或者其他值,那么就接着往下看吧^_^

      为什么main中得到的值是4,而不是7?
      首先,try...catch...finally语句中,finally语句块是在try或者catch语句块结束之前执行的。什么叫做结束之前?就是在遇到return或者结束花括号之前。没有return的情况下比较好理解,这里主要说的是遇到return而结束的情况。

      对于上面的代码,我们先看下结果7的由来:

  1. 第一步:从try语句块中【1】执行到【2】,这一过程a的值变为2,在【2】处发生“除零异常”,程序跳去执行catch语句块;
  2. 第二步:从catch语句块中【4】执行到【5】,这一过程a的值变为4,然后,根据上面所说的,在遇到结束标志return之前,程序跳去执行finally语句块;
  3. 第三步:从finally语句块中【7】执行到【8】,这一过程a的值变为7,然后,程序又折回到catch语句块中去结束catch块;
  4. 第四步:执行catch语句块中的【6】,返回a的值7。
     顺理成章,那么问题出在哪?
     对于有返回值的方法,如果返回值是基本类型,那么返回的是基本类型的值;如果返回值是对象类型,那么返回的是对象类型的引用。
     对于上面的代码,test()方法返回类型是基本数据类型int,因此返回的是int类型的实际值,而这个值是在执行【6】return之前就已经算出来的,而不是在执行完【8】之后才去计算的。即【5】【6】实际是类似这样的:

 System.out.println("catch block. a: " + a);//【5】
 int型返回值=a; 	      //【5.5】
 return int型返回值;	      //新【6】

      因此,其实应该是在【5.5】之后才转到【7】的,这样经过【8】回到【6】去结束catch时,就不会再计算了,直接返回【5.5】计算得到int值4。

     总而言之,你得有一双火眼金睛,要让【5.5】现出原形,不能让【6】蛊惑了。

      怎么理解【5.5】的存在性呢?看看下面一段代码:

public class TestException2 {
	
	public static void main(String[] args) {
		
		TestException te = new TestException();
		int a = te.test();
		System.out.println("call block. a: " + a);
	}
	
	public int test()
	{
		int a = 1;
		try
		{	//【1】
			a = a + 1;	//a:2
			System.out.println("try block. a: " + a);
			
			//this will cause an exception
			//int b = a / 0; 	//【2】
			return a + (1/0);	//【3】	
		}
		catch (Exception e)
		{//【4】
			a = a + 2;	//a:4
			System.out.println("catch block. a: " + a);//【5】
			return a;	//【6】
		}
		finally
		{//【7】
			a = a + 3;	//a:7
			System.out.println("finally block. a: " + a);//【8】
			//return a;	//【9】
		}	
		//return a;
	}//eof:test()
}

      这段代码和上面第一段代码的区别在于,没有了【2】,改在【3】处产生异常。这段代码,如果按照旧有的思路会推导出自相矛盾的结论的。按照旧有的思路,先执行完【8】,再去【3】计算表达式a + (1/0);的值,那么这个时候计算中出现的“除零异常”就不应该被捕获到了(因为整个try...catch...finally 的 finally 已经执行完,不会再重新执行catch了),而是应该抛出到test()方法外了,即main()方法的调用处了。


      至此,对于我们最初的问题,你应该也可以很确信地说答案是4了。
      可以对第一段代码稍加修改,自行观察返回值为非基本类型的情况,代码如下:

public class TestException3 {
	
	public static void main(String[] args) {
		
		TestException3 te = new TestException3();
		int[] a = te.test();
		System.out.println("call block. a[0]: " + a[0]);
	}
	 
	public int[] test()
	{
		int[] a = {1};
		try
		{//【1】
			a[0] = a[0] + 1; 	//a:2
			System.out.println("try block. a[0]: " + a[0]);
			
			//this will cause an exception
			int b = a[0] / 0; 	//【2】
			return a;		//【3】	
		}
		catch (Exception e)
		{//【4】
			a[0] = a[0] + 2;	//a:4
			System.out.println("catch block. a[0]: " + a[0]);//【5】
			return a;			//【6】
		}
		finally
		{//【7】
			a[0] = a[0] + 3;	//a:7
			System.out.println("finally block. a[0]: " + a[0]);//【8】
			//return a;//【9】
		}	
		//return a;
	}//eof:test()
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值