Java 中 try...catch...finally

一、try..catch..finally 介绍

try…catch 语句用于捕获异常。自上向下执行时,如果try中没有异常,则跳过catch。如果有异常则进入相对应的catch块中(发生什么异常就进入什么catch中,如果没有准确对应的则进入父类异常的catch中)。执行完catch中的语句,然后跳过其他catch,进入final。

try{
   int b=25/0;
   Thread.sleep(2000);
}
catch(ArithmeticException e){
 System.out.println("除零错误!");
}
catch(InterruptedException e){
 System.out.println("延时错误!");
}

上面的例子就进入了第一个catch。虽然Thread.sleep(2000);也有异常,但是没有执行到这个异常,就抛出了除零错误的异常。

1.finally 块用于清除 try 块中分配的任何资源,以及运行任何即使在发生异常时也必须执行的代码。 控制总是传递给 finally 块,与 try 块的退出方式无关。
2. catch 用于处理语句块中出现的异常,而 finally 用于保证代码语句块的执行,与前面的 try 块的退出方式无关。
3. catch 和 finally 一起使用的常见方式是:在 try 块中获取并使用资源,在 catch 块中处理异常情况,并在 finally 块中释放资源

二 finally 子句

引用自《深入Java虚拟机》

在解码中的finally子句在方法内部像一个“微型子程序“ 。Java虚拟机在try或者catch子句结尾处会“调用”finally 子句,finally子句执行完毕(不包括抛出异常,break,return,continue)微型子程序执行完毕,“返回”操作。

jsr指令使虚拟机跳转到微型子程序的操作码,Java虚拟机遇到jsr 指令会把返回地址压入栈没然后再微型子例程的开始处执行。微型子例程执行完毕,调用ret 指令,功能是执行从子例程中返回的操作。

注意返回值将会被保存在一个局部变量中,而不是直接使用返回值本身。稍后ret 指令会返回该局部变量。
原因:因为finally 中有可能存在break,return 语句,这样就无法执行ret 字节码,而jsr 指令压入栈中的返回地址需要被删除,这样的话就无法删除了。通过这种弹出保存在局部变量中的方式可以解决无法执行ret 指令时返回地址在栈中无法移除的问题。
也就是说通过异常退出finally子句,finally 子句结尾处的ret 指令永远不会执行到。

三, try、finally 执行顺序

``` public static String text1(){ String s = "test";
	try{			
		 s="try";
		 System.out.println("s="+s+" in Try");
		 return s;
		 
	}finally{
		s="finally";
		System.out.println("s="+s+" in Finally");
	}
}
//s=try in Try
//s=finally in Finally
//try

try…finally 的执行顺序(这里 finally 中没有 return):
  1、 执行try 中return之前的代码
  2、对 return 语句求值,将返回值存入局部变量s’(即try赋值给s’)中,执行jsr指令
  3、跳转到finally
  4、执行完finally ,最后执行ret 指令,将s’ (try)返回。
  
对于finally中也有return的代码:

	@SuppressWarnings("finally")
	public static  int text5(){
		
		try {
			return func1();
			
		}finally{
			return func2(); // 这里有return
			
		}
	}
	
	static int func1(){
		System.out.println("This is func1");
		return 1;
		
	}
	
	static int func2(){
		System.out.println("This is func2");
		return 2;
		
	}
	
//This is func1
//This is func2
//2

1,执行try中代码
2,遇到return,将返回值1 赋值给局部变量t
3,执行finally
4,执行finally中的return,在finally中将局部变量赋值为2
5,执行return
看起来就是,finally 中的return “覆盖了” try 块中的return。

	@SuppressWarnings("finally")
	public static String text2(){
		String s = "test";
		
		try{			
			 s="try";
			 System.out.println("s="+s+" in Try");
			 return s;
			 
		}finally{
			s="finally";
			System.out.println("s="+s+" in Finally");
			return s;
		}		
	}
	//s=try in Try
	//s=finally in Finally
	//finally

四,发生异常时,catch与finally的执行顺序与try相同

	@SuppressWarnings("finally")
	public static int test4(){
		int x=10;
		try{
			x=10/0;//发生异常,进入catch
			return x;//不被执行
			
		}catch(Exception e){
			x=x+2;
			return x;
			
		}finally{
			System.out.println("x="+x+" in Finally");
			return x;
			
		}
	}
	//x=12 in Finally
	//12

五, finally 是否可以修改 try 返回值

  • 如果finally正常结束。因为返回结果是保存在局部变量中的,即使在finally中改变,对于基本变量(不可变类型)来说不会影响局部变量中的值。
  • 如果返回值是可变类型,就会影响返回值。
	@SuppressWarnings("finally")
	public static StringBuffer test1(){
		StringBuffer s= new StringBuffer("try");
		
		try{
			System.out.println("s="+s+" in Try");
			return s;
			
		}catch(Exception E){
			return s;
		}finally{
			//x=x+10;
			s.append("+finally");
			System.out.println("s="+s+" in Finally");
		}
	}
	//s=try in Try
	//s=try+finally in Finally
	//try+finally  这里return的值已经被改变

因为stringBuilder 赋值给局部变量t’,与原来的t引用的是同一个对象,append 是在原对象上进行操作的(但String是不可变的,所以String 修改已经是另外一个对象了)

stackOverflow 上看到的解释
1、String 是不可变类型的。When you set s to “override variable s”, you set s to refer to the inlined String, not altering the inherent char buffer of the s object to change to “override variable s”.
2、You put a reference to the s on the stack to return to the calling code. Afterwards (when the finally block runs), altering the reference should not do anything for the return value already on the stack.

所以 return 可变类型时,finally 是否改变 return 值,需要看返回类型。

  • finally 中含有return 语句。try 中的return不被执行。改变了return的值

参考链接:
http://blog.csdn.net/ns_code/article/details/17485221;
http://www.cnblogs.com/gaochundong/p/try_finally_statement.html;
http://www.cnblogs.com/lanxuezaipiao/p/3440471.html#top;
http://stackoverflow.com/questions/16030858/why-does-changing-the-returned-variable-in-a-finally-block-not-change-the-return;
http://www.blogjava.net/fancydeepin/archive/2012/07/08/382508.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值