finally语句块是搭配着try语句块出现的,也就说必须有try语句块才会有finally语句块,但是并不是try语句块都会搭配有finally语句块出现,我们常见的更多是try...catch...

finally语句块一般出现的情况如下:

public int operation() { int result = 2016; /*statements*/ try { /*statements*/ } catch (Exception e) { /*statements*/ } finally { /*statements*/ } } 

一、finally语句块的执行时机

  • finally语句并不是每次都执行,只有线程执行过try语句块,finally语句块才会执行。如果线程执行到try语句块之前就return的话,finally语句是不会执行的。如例程中第一种情况,在try语句块之前执行return语句将会直接退出函数。
  • 只要线程进入过try语句块,不论有没有抛出异常,finally语句块都会执行。如例程中的第二种和第三种情况,线程执行进入try语句块,不管有没有出现异常,finally语句都正常执行。
  • finally 语句块是在结果返回之前执行的。根据第二种和第三种情况,可以发现finally语句执行在main函数打印结果之前。
public class Test { public static void main(String[] args) { System.out.println("return before try"); System.out.println("value: " + test(1)); System.out.println("return after try"); System.out.println("value: " + test(0)); System.out.println("return after try catch"); System.out.println("value: " + test()); } public static int test(int i) { if (i == 1) return 0; try { System.out.println("try block"); return i; } finally { System.out.println("finally block"); } } public static int test(){ int i = 1; try { System.out.println("try block"); i = 1 / 0; return 1; }catch (Exception e){ System.out.println("exception block"); return 2; }finally { System.out.println("finally block"); } } } 

执行结果

return before try
value: 0 return after try try block finally block value: 0 return after try catch try block exception block finally block value: 2 

二、finally语句块对返回结果的影响
上面的例子为了不影响读者理解,在finally语句中没有做任何可能会影响到返回结果的操作。但是在finally语句块中对返回结果进行操作的话,会不会对返回结果造成影响就要分情况而论了。在学习接下来这部分知识之前,笔者是坚持认为finally语句对返回结果进行操作,是肯定会影响返回结果的值的,毕竟根据上面的理解,finally语句块执行在结果返回之前嘛,随着深入学习,笔者发现这里面还是有需要注意的地方的。先看一段例程:

public class Test { public static void main(String[] args) { System.out.println("value : " + getValue()); } public static int getValue() { int i = 1; try { return i; } finally { i++; } } } 

执行结果:

value : 1

按照之前的理解,这个程序执行得有点不按套路出牌啊,执行完try语句之后,程序先不返回,接着执行finally语句块,做自增操作,返回值应该是2啊,怎么会是1呢?我不知道各位读者这会什么心情,反正当时我看到这结果的时候,用一脸懵逼来形容是毫不为过。

结果查阅资料,发现这个地方Java里面是有特殊处理的,下面这段话是抄的:
“Java 虚拟机会把 finally 语句块作为 subroutine直接插入到 try 语句块或者 catch 语句块的控制转移语句之前。但是,还有另外一个不可忽视的因素,那就是在执行 subroutine之前,try 或者 catch 语句块会保留其返回值到本地变量表中。待 subroutine 执行完毕之后,再恢复保留的返回值到操作数栈中,然后通过 return 或者 throw 语句将其返回给该方法的调用者。”

也就是说在try...catch...中执行到return语句的时候,会先把需要返回的数据缓存下来,再去执行finally语句块,执行完finally语句块之后,再将缓存的数据作为结果返回。这样看来上面例程的执行结果就说得过去了。是不是好开心,感觉一下子豁然开朗了呢。不要着急,咱们再入一个例程:

public class Test { static class Monitor { int flag; public Monitor(int flag) { this.flag = flag; } public void setFlag(int flag) { this.flag = flag; } public int getFlag() { return this.flag; } } public static void main(String[] args) { Monitor monitor = getValue(); System.out.println("flag : " + monitor.getFlag()); } public static Monitor getValue() { Monitor monitor = new Monitor(0); try { return monitor; } finally { monitor.setFlag(1); } } } 

执行结果:

flag : 1

不是说在执行finally语句之前会把结果缓存的吗?为什么返回的结果会是1,应该是0才对的啊。其实这个地方出现疑问是因为不了解缓存到底存的是什么。这两个例程在我们的理解上产生冲突,是因为这两个例程中,finally语句块操作的是两种类型的变量,一个是基本类型,一个是对象类型。这两种类型的变量的存储方式是不一样的。int等基本类型的变量,在变量对应的内存中直接存放的就是该变量的值,而对象类型的变量,在其对应的内存中存放的是对象所在的地址。执行finally语句之前,Java确实对二者都进行了缓存,缓存的是变量对应的内存中存放的数据,于基本类型而言,缓存的是值,于对象类型而言,缓存的是对象所在内存区块的地址。我们在finally语句中进行操作时,不会影响缓存中存放的数据,这样无论我们对基本类型的值如何操作,返回值始终是之前的值,但是对象类型是不一样的,缓存的数据不变只能保证缓存数据地址指向的一直是同一个对象,finally语句块中对这个对象进行操作,是完全可以影响到对象的属性的。

看到这,暂时算是豁然开朗了,也不知道有没有没挖出来的坑,如果有的话,还请各位大牛不吝赐教。

转载于:https://www.cnblogs.com/igoodful/p/9661680.html

finally语句块相关推荐

  1. WCF客户端不能用在Using语句块中,因为它可能会抛出不可预知的异常。即使你捕获了异常,仍有可能一直保持连接。...

    WCF客户端不能用在Using语句块中,因为它可能会抛出不可预知的异常.即使你捕获了异常,仍有可能一直保持连接.让我们来看看形成这一问题的历史原因,并提出几个补救措施. 在.NET中,资源管理的基础就 ...

  2. R语言嵌套的ifelse语距:将一条If语句放在另一条If语句中,该语句作为嵌套的If else调用。If else语句允许我们根据表达式结果(TRUE或FALSE)打印不同的语句,执行不同的语句块

    R语言嵌套的ifelse语句:将一条If语句放在另一条If语句中,该语句作为嵌套的If else调用.If else语句允许我们根据表达式结果(TRUE或FALSE)打印不同的语句,执行不同的语句块 ...

  3. java多层catch语句_Java异常之catch语句块

    今天在阅读项目代码时看到如下奇怪的代码,以为是竖线 | 可以作为多类型赋值,经过网上搜索才知道是Java SE 7新增的功能:一个catch捕获多种类型的异常.原文是Java官方的文档,现翻译如下.红 ...

  4. python使用什么来表示不同级别的语句块-python通过什么来区分不同的语句块?

    python是通过缩进格式来区分不同语句块的.Python语言利用缩进表示语句块的开始和退出(Off-side规则),增加缩进表示语句块的开始,而减少缩进则表示语句块的退出. Python语句块 1. ...

  5. python使用什么格式划分语句块-python以什么划分语句块

    语句块是在条件为真(条件语句)时执行或者执行多次(循环语句)的一组语句: 在代码前放置空格来缩进语句即可创建语句块,语句块中的每行必须是同样的缩进量:(推荐学习:Python视频教程) 缩进:Pyth ...

  6. python使用什么来表示不同级别的语句块-Python

    [简答题] [简答题]请写出下列程序的运行结果: def add_b(): global b b = 42 def do_global(): #global b b = b + 10 print(b) ...

  7. 一起谈.NET技术,WCF的问题和Using语句块

    WCF客户端不能用在Using语句块中,因为它可能会抛出不可预知的异常.即使你捕获了异常,仍有可能一直保持连接.让我们来看看形成这一问题的历史原因,并提出几个补救措施. 在.NET中,资源管理的基础就 ...

  8. python表示语句块采用_python中什么是语句块?

    在python中,语句块是在条件为真(条件语句)时执行或者执行多次(循环语句)的一组语句.在代码前放置空格来缩进语句即可创建语句块,语句块中的每行必须是同样的缩进量. Python的基本语法--语句块 ...

  9. 关于 Java 中 finally 语句块的深度辨析

    可不能小看这个简单的 finally,看似简单的问题背后,却隐藏了无数的玄机.接下来我就带您一步一步的揭开这个 finally 的神秘面纱. 问题分析 首先来问大家一个问题:finally 语句块一定 ...

  10. C++ Primer 5th笔记(chap 18 大型程序工具)函数 try 语句块与构造函数

    1. 问题 构造函数在进入函数体之前首先执行初始化列表.因为在初始值列表抛出异常时构造函数体内的try语句块还未生效 1.1 解决方法 {// 这是处理构造函数初始值错误的唯一方法template & ...

最新文章

  1. RDS for MySQL 5.7 备份恢复为本地实例
  2. Apache/Nigix + Tomcat + 负载均衡
  3. android 开源fc模拟器_星标 4.5K!又一个跨端框架,腾讯开源内部跨端统一开发框架:Hippy...
  4. 神经网络架构搜索(NAS)综述 | 附AutoML资料推荐
  5. 判断字符串是不是application/x-www-form-urlencoded字符串(URL编码格式的字符串)
  6. xp硬盘上安装ubuntu12.04双系统
  7. 【转】Linux下发生段错误时如何生成core文件
  8. JXSE 2.5 : What's Cool #5 -- java.util.concurrent
  9. numpy 下载安装
  10. 两年数据对比柱形图_堆积柱形图+散点图=数据对比完美呈现(附视频)
  11. CPU单线程性能排行榜/天梯图
  12. 软考岗位设置与岗位描述
  13. vue $confirm 自定义图标及修改图标颜色
  14. 没有基础可以学画插画吗?怎么学?
  15. echarts图表x轴基准线(平行y轴)
  16. 《商业模式》读书笔记
  17. python与js之间实现通信
  18. .NET类比学JAVA之访问SqlServer数据库
  19. 《软件测试经验与教训》读书笔记---第二章
  20. Python3教程:copy模块详细用法

热门文章

  1. 鸿蒙os 2.0 beta 3,华为发布鸿蒙OS2.0手机开发者Beta3版本
  2. MaxCompute 图计算用户手册(上) 1
  3. php中json是做什么用的,json是什么意思?是用来干嘛的?
  4. Kdevelop的安装与汉化
  5. 【腾讯优测干货分享】Android内存泄漏的简单检查与分析方法
  6. 到腾讯工作一年了,从失业到上天
  7. Hystrix断路器入门1
  8. 3次Bezier曲线求交
  9. 《白帽子讲web安全》第3章 跨站脚本攻击(XSS)
  10. DoTween常用方法举例总结