您的位置:首页 > 编程语言 > Java开发

六个例子彻底理解finally语句块

2016-07-28 20:26 483 查看

六个例子彻底理解
finally
语句块

这篇博客主要弄清楚两个问题

   1.
finally
块中的代码是否一定会执行

   2.
finally
块中的代码什么时候被执行

首先开始第一个:

finally
块中的代码一定会被执行么?

答案是否定的,主要有以下几种情况:

  1.try之前发生异常或者直接结束的情况.

  
finally
是与
try
,
catch
配套使用的,
finally
生效的最大的前提就是得能进行到try语句内,例如以下这种情况就属于没有进入到
try
然后
finally
不执行的情况:

int i = 5 / 0;
try {
System.out.println("Try block");
} catch (Exception e) {
System.out.println("Catch block");
}finally {
System.out.println("Finally block");
}


  2.
try
语句内强制退出程序

  比较好理解,如下:

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

//输出
Try block


finally
是什么时候执行的?

先看实例:以下程序的输出结果是什么?

public static int test() {
try {
return 1;
} catch (Exception e) {
return 0;
} finally {
System.out.println("Finally block");
}
}

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


结果:

Finally block
1


为何会出现这种情况?

Java
语言的异常处理中,
finally
的作用就是为了保证无论出现什么情况,
finally
里面的代码一定会执行(当然并不能满足所有的情况).

由于程序执行
return
就意味着结束对当前函数的调用并且跳出这个函数,因此所有的必须要执行的语句都应该在
return
之前执行(除非遇到
exit
函数).因此finally块中的函数也是要在return之前执行的.

如下图:



至于进行的什么处理下文再说

再看一个实例:

public static int test() {
try {
return 1;
} catch (Exception e) {
return 0;
} finally {
System.out.println("Finally block");
return 3;
}
}

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


结果:

Finally block
3


这个实例说明如果
finally
块内也包含
return
语句,那么
finally
内的
return
语句会覆盖
try-catch
内的
return
结果

再来一个例子:

public static int test() {
int result = 0;
try {
result = 1;
return result;
} catch (Exception e) {
result = 2;
return result;
} finally {
result = 3;
System.out.println("Finally block");
}
}

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


结果:

Finally block
1


先不急于解释这种现象,再看一个类似的例子

public static StringBuilder test() {
StringBuilder builder = new StringBuilder("hello");
try {
return builder;
} catch (Exception e) {
return null;
} finally {
builder.append("world");
System.out.println("Finally block");
}
}

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


结果:

Finally block
hello world


对比前面两个例子是不是更加疑惑了,但其实原因特别简单:

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

  因此,对于前一个例子当中,由于是基本类型的数据,所有复制的是变量的数值,并且这个复制过程是在执行
finally
之前的,所有
finally
内修改基本类型的值没能生效,因为要输出的值早已经确定了

  而后一个例子中是引用类型,复制的时候只是复制的对象的地址,
finally
对变量进行修改的时候改变了对应的对象的属性,输出的时候按照地址获取属性,获取的是修改后的属性,所以是有影响的.

#现在知道前面的处理是啥了.如图:



是不是已将明了了一些了,那么再来看一个例子:

public static String test() {
StringBuilder builder = new StringBuilder("hello");
try {
return builder.toString();
} catch (Exception e) {
return null;
} finally {
builder.append(" world");
System.out.println("Finally block");
}
}

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


输出结果

Finally block
hello


细心的同学应该不会被坑到,
finally
内的修改没有生效,原因在于复制的时候不是复制的
StringBuilder
的地址,而是一个字符串的地址,当然也有同学会说String也是引用类型,
finally
内的代码修改了对应地址的数据,但是要注意
String
是一个不可变类,
builder
调用的
append
方法并没有对
"hello"
进行任何修改,之前
String
的地址对应的值是不会变化的.所以
finally
内的修改没有生效.有的同学有疑惑,关于
String
,
StringBuilder
等对象的区别请参考这篇博客:Character , String , StringBuffer , StringBuilder , StringTokenizer 的区别.

为了对比那再看一个例子:

static class TestEntity {
String mString;
StringBuilder mBuilder;

public TestEntity(String string, StringBuilder builder) {
mString = string;
mBuilder = builder;
}

public StringBuilder getBuilder() {
return mBuilder;
}
}

public static StringBuilder test() {
TestEntity entity = new TestEntity("hello", new StringBuilder("world"));
try {
return entity.getBuilder();
} catch (Exception e) {
return null;
} finally {
entity.getBuilder().append(" world");
System.out.println("Finally block");
}
}

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


应该已经猜到结果了

Finally block
world world


原因上面都提到了,
StringBuilder
是引用类型并且是可变的,所以
finally
内的修改会生效.

结束~

有不足的地方欢迎指出,另外建了个新手交流
Android
开发的QQ群,欢迎加入.

群号:375276053

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 异常捕获