一道关于finally的面试题

题目

下面程序是否存在问题?如果存在,请指出问题所在,如果不存在,请说明输出结果。

package InterView;

public class Test1 {

	private static String result = "";

	public static void main(String[] args) {
		f(0);
		f(1);
		System.out.println(result);

	}

	public static void f(int i) {
		try {
			if (i == 1) {
				throw new Exception("exception message");
			}

		} catch (Exception e) {
			result += "2";
			return;
		} finally {
			result += "3";
		}
		result += "4";

	}

}

答案

不存在问题,输出结果为3423。

解析

在java语言的异常处理中,finally语句块的作用就是为了保证无论出现什么情况,finally块里的代码一定会被执行。由于当程序执行到return的时候,意味着结束对当前函数的调用并跳出这个函数体,任何语句要执行都只能在return前执行(除非碰到exit函数),因此,finally块里的代码也是在return前执行的。此外,如果try-finally或者catch-finally中都有return,则finally块中的return语句将会覆盖别的return语句,最终返回调用者那里的是finally语句块中return的值。

下面通过一个例子来说明这个问题。

package InterView;

public class Test2 {

	public static void main(String[] args) {
		int result = testFinally();
		System.out.println(result);

	}

	private static int testFinally() {

		try {
			return 1;

		} catch (Exception e) {
			return 0;
		} finally {
			System.out.println("execute finally");
		}

	}

}

运行结果为: 

从上面例子中可以看出,在执行return语句前确实执行了finally块中的代码。紧接着,在finally块里面放置return语句,例子如下:

package InterView;

public class Test2 {

	public static void main(String[] args) {
		int result = testFinally();
		System.out.println(result);

	}

	private static int testFinally() {

		try {
			return 1;

		} catch (Exception e) {
			return 0;
		} finally {
			System.out.println("execute finally");
			return 3;
		}

	}

}

运行结果:

从以上运行结果可以看出,当finally块中有return语句时,将会覆盖函数中其他return语句。

此外,由于在一个方法内部定义的变量都存储在栈中,当这个函数运行结束后,其对应的栈就会被回收,此时,在其方法体中定义的变量将不存在了,因此,return在返回的时候不是直接返回变量的值,而是复制一份,然后返回。

因此,对于基本类型的数据,在finally块中改变return放入值对返回值没有任何影响,而对于引用类型的数据,就有影响。

下面通过一个例子来说明这个问题。

package InterView;

public class Test3 {

	public static void main(String[] args) {
		int resultVal = testFinally1();
		System.out.println(resultVal);
		StringBuffer buffer = testFinally2();
		System.out.println(buffer);

	}

	private static StringBuffer testFinally2() {
		StringBuffer s = new StringBuffer("hello");
		try {
			return s;
		} catch (Exception e) {
			return null;
		} finally {
			s.append(" World");
			System.out.println("execute finally2");
		}

	}

	private static int testFinally1() {
		int result = 1;
		try {
			result = 2;
			return result;
		} catch (Exception e) {
			return 0;
		} finally {
			result = 3;
			System.out.println("execute finally1");
		}

	}

}

运行结果:

 

 程序在执行到return语句的时候,会首先将返回值存储在一个指定的位置,然后执行finally代码块,最后再返回。在方法testFinally1中调用return前,首先把result的值2存储在一个指定的位置,然后执行finally块中的代码,此时修改result的值将不会影响到程序的返回结果。testFinally2中,在调用return前,首先把s存储到一个指定的位置,由于s为引用类型,因此,在finally块中修改s将会修改程序的返回结果。

引申

出现在java程序中的finally代码块是否一定会执行?

下面给出两个finally代码块不会执行的例子。

1、当程序在进入try语句块之前就出现异常,会直接结束,不会执行finally块中的代码。

如下例所示:

package InterView;

public class Test4 {

	public static void main(String[] args) {
		testFinally();

	}

	private static void testFinally() {
		int i = 5 / 0;
		try {
			System.out.println("try block");
		} catch (Exception e) {
			System.out.println("catch block");
		} finally {
			System.out.println("finally block");
		}

	}

}

运行结果:

程序在执行int i=5/0时抛出异常,导致没有执行try块,因此,finally块也就不会被执行。

2、当程序在try块中强制退出时,也不会执行finally块中的代码,如下例所示:

package InterView;

public class Test4 {

	public static void main(String[] args) {
		testFinally();

	}

	private static void testFinally() {

		try {
			System.out.println("try block");
			System.exit(0);
		} catch (Exception e) {
			System.out.println("catch block");
		} finally {
			System.out.println("finally block");
		}

	}

}

运行结果:

 

上例在try块中通过调用System.exit(0)方法强制退出了程序,因此,导致finally块中的代码没有被执行。

总结

从上面分析可以看出,在try/catch/finally语句执行的时候,try块会首先执行,如果有异常发生,则进入catch块来匹配异常,当匹配成功后则执行catch块中的代码,不管有无异常发生,都会执行finally块的代码(即时catch块中有return语句,finally块中的代码仍会执行);当有异常发生后,catch和finally块进行处理后程序就结束了,就算finally块后面有代码也不会执行,如果没有异常发生时,在执行完finally块的代码后,后面的代码还会继续执行。

 (ok,我们继续回到今天的这道题目。

在调用f(0)方法的时候,没有异常,因此,直接执行finally块和后面的代码块,方法的返回值为“34”;

在调用f(1)方法的时候,产生异常,因此,只会执行catch块和finally块中的代码,方法返回值为“23”;

因此,这个程序的运行结果为3423。)

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值