前言:有java编程基础的人对java的异常处理机制都会有一定了解,而且可能感觉使用起来也比较简单,但如果在try catch finally语句块中遇到return语句,开发者可能就会遇到一些逻辑问题,甚至步入编程的陷阱。不信,我们先看看一段小程序,读者可以分析其逻辑然后猜测其输出结果:

public class Test {

public static void main(String[] args) {

Test t = new Test();

System.out.println(t.Test1());

}

public boolean Test1() {

boolean b = true;

try {

int i = 10 / 0;

System.out.println("i = " + i);

return true;

} catch (Exception e) {

System.out.println(" -- catch --");

System.out.println("b:" + b);

return b = false;

} finally {

System.out.println(" -- finally --");

System.out.println("b:" + b);

}

}

}

请先停止继续阅读,试着说出其运行结果。

如果你不能很自信地正确说出这段程序的执行逻辑和结果,那本文就值得你一读,如果你可以,请忽略本文。

执行结果是:

– catch –

b:true

– finally –

b:false

false

你说对了吗?

正文

首先我们了解java的异常处理机制中try、catch、finally的基本执行逻辑。

  • try:包裹可能引发异常的代码
  • catch:可以有多个catch块,一个代码块对应一种异常类型,表明该catch块用于处理此类型的异常。
  • finally:主要用于回收在try块里使用的物理资源(比如数据库连接、网络连接和磁盘文件等),这些物理资源必须显示回收,因为java的垃圾回收机制不会回收任何的物理资源,垃圾回收机制只回收堆内存中对象所占用的内存。异常机制保证finally块内的代码总是被执行,除非在try块或者catch块中调用了退出虚拟机的方法(即System.exit(1);),此时程序直接退出,不再执行finally块。

首先明确其语法结构:

1. try块必存在, catch块和finally块都是可选的,但两者需至少出现其中之一,也可以同时出现;

2. 可以有多个catch块,捕获父类异常的catch块必须位于捕获子类异常的后面,即设计多个catch块捕获异常时要先捕获小的异常,再捕获大的异常。一般,try块后只有一个catch块会被执行,绝不可能有多个catch块被执行,除非使用continue开始下次循环时,再次执行到这个try、catch块,而捕获处理其他catch的异常;

3. 多个catch块必须位于try块之后,finally块必须位于所有catch块之后。

下面我们分情况讨论try、catch、finally中含有return的情况。

示例一(try、catch、finally中都有return):

public class Test {

public static void main(String[] args) {

Test t = new Test();

System.out.println(t.Test1());

}

public boolean Test1() {

try {

int i = 10 / 0; // 抛出 Exception,try中其他代码不执行,进入catch

System.out.println("i = " + i);

return true;

} catch (Exception e) {

System.out.println(" -- catch --");

return false;

} finally {

System.out.println(" -- finally --");

return true;

}

}

}

Eclipse中,这段代码会出警告:finally block does not complete normally。译为:finally块不能正常完成。Java不建议在finally块中使用renturn或throw等导致方法终止的语句,否则将会导致try块、catch块中的return、throw语句失效。但是仍然可以执行,结果为:

– catch –

– finally –

true

这里最后打印的true即时finally中返回的true。至于为什么会覆盖,这个涉及到JVM底层字节码的具体实现和一些指令操作,如果没有JVM和计算机组成原理以及操作系统的相关基础知识是较难以理解的,有余力的开发者可以深入研究。

实例二(try、catch中有return,finally中无):

public class Test {

public static void main(String[] args) {

Test t = new Test();

System.out.println(t.Test1());

}

public boolean Test1() {

try {

int i = 10 / 0; // 抛出 Exception,try中其他代码不执行,进入catch

System.out.println("i = " + i);

return true; // 不会执行

} catch (Exception e) {

System.out.println(" -- catch --");
return false; // Exception 抛出,获得了返回false的机会

} finally {

System.out.println(" -- finally --");

}

}

}

执行结果:

– catch –

– finally –

false

断点调试可发现其逻辑:在finally执行后,又回到catch语句里面的return上,然后返回这句中的false。然后,很多人就会认为,甚至很多技术博客都写到:只有finally块执行完成之后,才会回来执行try或者catch块中的return语句。 但是!!真的是这样吗?也许是说这话的人知道意思但表达不够清楚,以至于让笔者觉得是误人子弟,try、catch中的rerun语句的逻辑是否执行?执行完finally块后一定会返回去执行try、catch吗?我们回过头来看开篇的那段代码:

public class Test {

public static void main(String[] args) {

Test t = new Test();

System.out.println(t.Test1());

}

public boolean Test1() {

boolean b = true;

try {

int i = 10 / 0;

System.out.println("i = " + i);

return true;

} catch (Exception e) {

System.out.println(" -- catch --");

System.out.println("b:" + b);

return b = false;

} finally {

System.out.println(" -- finally --");

System.out.println("b:" + b);

}

}

}

代码中我们将catch中的return语句加上了一个赋值操作,断点调试,可以发现,程序执行到int i = 10 / 0; 语句后跳出catch块,并完整执行到return b = false; 然后进入finally块,执行两条输出语句,第二条System.out.println(“b:” + b);这里的b变成了false!,说明之前return中的赋值语句有执行,执行完finally后,程序再次进入catch中的return,返回给调用者。所以事实是,当Java程序执行try块、catch块遇到return语句时,当系统执行完return语句之后,并不会立即结束该方法,而是去寻找该异常处理流程中是否包含finally块,如果没有finally块,方法终止,返回相应的返回值。如果有finally块,系统立即开始执行finally块——只有当finally块执行完成后,系统才会再次跳回来根据return语句结束方法。如果finally块里使用了return语句来导致方法结束,则finally块已经结束了方法,系统不会跳回去执行try、catch块里的任何代码。

依照此标准,下列程序应该输出什么?

public class Test {

public static void main(String[] args) {

Test t = new Test();

System.out.println(t.test());

}

public static int test() {

int count = 5;

try {

return ++count;

} catch (Exception e) {

// TODO: handle exception

} finally {

System.out.println("finally()执行");

return count++;

}

}

}

答案是:

finally()执行

6

测验:

public class Test {

public static void main(String[] args) {

int a = test();

System.out.println(a);

}

public static int test() {

int count = 5;

try {

throw new RuntimeException("测试异常1");

}catch (RuntimeException e) {

System.out.println(e.toString());

throw new RuntimeException("测试异常2");

}catch (Exception e) {

System.out.println(e.toString());

return 2;

} finally {

System.out.println("finally()执行");

return count;

}

}

}

运行结果:

java.lang.RuntimeException: 测试异常1

finally()执行

5

如果注释掉语句:return count;

则运行结果是先打印出

“java.lang.RuntimeException: 测试异常1

finally()执行”

后再抛出测试异常2,程序异常结束。

简而言之,程序在catch中执行throw语句时并不会立即抛出异常,而是去寻找该异常处理流中是否包含finally块。如果没有finally块,程序立即抛出异常;如果有finally块,程序立即开始执行finally块——只有当finally块执行完成后,系统才会再次跳回来抛出异常。如果finally块里使用return语句来结束方法,系统将不会跳回catch块去抛出异常。

如果去掉catch块和finally中的return语句,则运行结果为:

先打印“System.out.println(“finally()执行”);”再抛出异常1,方法异常结束。

如果去掉catch块,保留finally中的return语句,则运行结果为:

“finally()执行

5”

方法正常结束,不会再抛出异常。

实践是检验真理的唯一标准。学会用质疑的眼光求真,用踏实的态度去实践,是每一个成熟的技术人员所必须的。

请尊重原创,转载请注明出处:

http://blog.csdn.net/daijin888888/article/details/48369809

Java中try catch finally语句中含return语句的执行情况总结-编程陷阱的更多相关文章

  1. java finally中含return语句

    <java核心技术卷一>中提到过:当finally子句包含return 语句时(当然在设计原则上是不允许在finally块中抛出异常或者 执行return语句的,我不明白为何java的设计 ...

  2. Java中try、finally语句中有return时的执行情况 [转]

    原文:http://kingj.iteye.com/blog/1436761 在Java中当try.finally语句中包含return语句时,执行情况到底是怎样的,finally中的代码是否执行,大 ...

  3. try,catch,finally含return时的执行顺序及丢失的伪例

    最近面试遇到一个之前也看到过但没去看一下的问题.就是有return情况下的try,catch,finally的执行顺序. 今天写了下. 先看顺序问题.总结如下: 一:finally中没有写return ...

  4. 0016 Java学习笔记-异常-如果try-catch-finally中都存在return语句会怎样?

    上午在搜索"System.runFinalization"的时候,搜到 http://www.cnblogs.com/Skyar/p/5962253.html ,其中有关于try- ...

  5. try、catch、finally都有return语句时执行哪个

    任何执行try 或者catch中的return语句之前,都会先执行finally语句,如果finally存在的话.如果finally中有return语句,那么程序就return了,所以finally中 ...

  6. 面试题:try,catch,finally都有return语句时执行哪个 已看1

    1.不管有木有出现异常,finally块中代码都会执行: return 先执行 把值临时存储起来, 执行完finally之后再取出来 值是不会改变的2.当try和catch中有return时,fina ...

  7. finall语句是在return语句执行前被执行还是执行后被执行?

    finally对try...catch的影响和执行时间 一.finally语句不被执行的两种情况 我们在学习抛出异常的时候学习到了finally语句块,这个语句块一般会被执行,但是有两种情况下不被执行 ...

  8. Java问题解读系列之基础相关---含继承时的执行顺序

    今天来研究一下含继承.静态成员.非静态成员时Java程序的执行顺序: 一.不含继承,含有静态变量.静态代码块 创建一个子类,该类包含静态变量.静态代码块.静态方法.构造方法 /** * @create ...

  9. java中 try catch finally和return联合使用时,代码执行顺序的小细节

    代码1测试 public static void main(String[] args) { aa(); } static int aa() { try { int a=4/0; } catch (E ...

随机推荐

  1. Chrome 地址栏如何设置显示 http/https 和 www

    首先在 chrome 地址栏输入以下地址 chrome://flags/#omnibox-ui-hide-steady-state-url-scheme-and-subdomains 然后使用 Ctr ...

  2. uva11401:Triangle Counting 递推 数学

    uva11401:Triangle Counting 题目读不清楚的下场就是多做两个小时...从1-n中任选3个不重复数字(不重复啊!!坑爹啊!)问能组成三角形的有多少个, 显然1~n能组成的三角形集 ...

  3. 跟我一起做一个vue的小项目(九)

    接下来我们进行的就是城市列表页面数据额动态渲染. 也是在mock数据,进行动态渲染 //city.json { "ret": true, "data":{ &q ...

  4. 如何在vue项目中使用md5.js及base64.js

    一.在项目根目录下安装 npm install --save js-base64 npm install --save js-md5 二.在项目文件中引入 import md5 from 'js-md ...

  5. LUOGU P2441 角色属性树

    题目描述 绪萌同人社是一个有趣的组织,该组织结构是一个树形结构.有一个社长,直接下属一些副社长.每个副社长又直接下属一些部长--. 每个成员都有一个萌点的属性,萌点属性是由一些质数的萌元素乘积构成(例 ...

  6. Hackerrank--Ashton and String(后缀数组)

    题目链接 Ashton appeared for a job interview and is asked the following question. Arrange all the distin ...

  7. Django ORM中的查询,删除,更新操作

    ORM查询操作 修改views.py文件 from django.shortcuts import render, HttpResponse from app01 import models from ...

  8. webpack学习之—— Loaders

    loader 用于对模块的源代码进行转换.loader 可以使你在 import 或"加载"模块时预处理文件.因此,loader 类似于其他构建工具中“任务(task)”,并提供了 ...

  9. hack 记录

    0.寻找信号强的wifi,对于隐藏ssid 的可通过嗅探 1.wifi密码:wifi万能钥匙.minidwep-gtk.aircrack-ng 2.对于绑定mac地址的安全设置,可通过对活动的客户端网 ...

  10. OpenLayers添加地图标记

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head ...