前言:有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中return不运行的情况_Java中try catch finally语句中含return语句的执行情况总结-编程陷阱...相关推荐

  1. 为什么java我点击运行却没有_java – 为什么我的jar文件没有双击启动?

    我在双击时启动一个jar文件时遇到麻烦(并用 java SE打开),jar从命令行启动就好了,我创建的其他罐子从双击启动就好了. 我使用eclipse导出器导出了jar文件,我使用了runnable ...

  2. maven install后,java -jar XXXX.jar运行---找不到主类问题 以及 虚拟机中执行jar包后 访问页面出现Java heap space等其他问题

    这是前几天遇到的问题了,当天晚上想写下来来着,后来有事情就一直搁置到现在了. 由于我想将SpringCloud项目都导出jar包在虚拟机上运行,然后本地访问,所以先将SpringCloud中的注册中心 ...

  3. java map移除key为空_Java实现过滤掉map集合中key或value为空的值示例

    本文实例讲述了Java实现过滤掉map集合中key或value为空的值.分享给大家供大家参考,具体如下: import java.util.Collection; import java.util.H ...

  4. java代码没错却运行不了_Java代码没错误,tomcat能正常运行,但是我的项目主页却一直显示不了,显示404错误...

    重新在别人的电抄脑上配置一次环境变量bai 配置环境变量 点击du计算机->高级系zhi统设置->环境变量dao-> 在第一个中新建一个 变量:classpath 值:.;(记住是分 ...

  5. java如何调用父类的实例对象_java子类调用父类的方法中包含子类重写的实例方法...

    java子类调用父类的方法中包含子类重写的实例方法 # 看题目是不是很绕,这个我也不知道怎么才能更简单的表达了 # 先看代码: public class Common { public static ...

  6. java提取字符串中的数字并升序排序_java小练习,将字符串中的数值进行升序排序...

    问题引出:正常情况下用int数组可以直接用sort()方法排序,但是字符串不能. 思路:将字符串变成字符串数组,字符串数组变成int数组,再进行排序,排序后再变成字符串 将字符串中的数值从小到大排序 ...

  7. java多态的理解(运行时多态)_Java多态的理解

    什么是多态 面向对象的三大特性:封装.继承.多态.从一定角度来看,封装和继承几乎都是为多态而准备的.这是我们最后一个概念,也是最重要的知识点. 多态的定义:指允许不同类的对象对同一消息做出响应.即同一 ...

  8. java获取word固定位置的值_java 实现保存Word文档中指定位置的数据,又保存整篇文档...

    1:需求 用户在线编辑完word 文档后希望保存整篇文档, 同时把保存文档中指定位置的数据 2:方案 用 pageoffice  实现既保存Word文档中指定位置的数据,又保存整篇文档 4:核心思想及 ...

  9. java上怎么把文字加边框_Java如何对Word文档中的文本应用边框?

    在Java编程中,如何对Word文档中的文本应用边框? 注意:需要访问网址:http://poi.apache.org/download.html , 下载一个Apache POI软件包.这里下载最新 ...

  10. java中的依赖是啥意思_java – “ – ”(箭头)在gradle的依赖图中是什么意思?

    我试图运行一些Android测试,但编译器抱怨存在多个dex文件. Multiple dex files define Lorg/hamcrest/MatcherAssert; 所以我试图过滤重复的依 ...

最新文章

  1. usaco letter game
  2. MATLAB_no.2:关于眼睛的_cutab=[cutab;a b];_cutab(:,2)-cutab(:,1):
  3. python中copy怎么用_python中的拷贝copy模块怎么使用?
  4. 美国25大最具价值博客网站出炉
  5. Scalable, Distributed Systems Using Akka, Spring Boot, DDD, and Java--转
  6. JDBC之在分层结构中实现业务
  7. java8中stream最实用总结和调试技巧
  8. HarmonyOS快速开发入门
  9. 7.MongoDB java CRUD
  10. TCP 和 UDP,哪个更胜一筹
  11. alexa语音实现_如何通过语音删除Alexa录音
  12. linux+shell+func,Linux shell编程笔记总结
  13. VGGnet论文解读及代码实现
  14. 都说如果朋友都是有钱人,你也会更容易发财
  15. mysql8 create table 语法错误_MySQL8.0 Window Function 剖析
  16. 算法设计与分析基础(三)
  17. android 支付宝 记账本,使用支付宝记账----懒人的最佳记账模式
  18. 怎样修改一篇简历 简历怎么写
  19. mysql数据库出现2003-Can‘t connect to MySQL server on ‘localhost‘ (10061)的解决方法
  20. 一个骗人的恶劣网站: GPS 定位好友 的传说 ( 其中一个域名是 ipl38.com 诈骗:利用手机号码GPS卫星追踪你的他(她)在什么位置

热门文章

  1. 优思学院:通俗地谈谈FMEA
  2. 我与我的专业计算机网络作文,我与网络的作文
  3. Java密码连接redis
  4. linux卸载360软件下载,在Deepin及其他Linux系统中使用命令卸载360安全卫士的方法...
  5. linux find typelinux find用法(转)
  6. Windows 10 配置OpenGL ES 3.0 环境
  7. 什么是SAN网络?SAN网络上的存储备份和恢复怎么操作?SAN 测试网络存储与服务器架构架构优化
  8. Fortran七七八八
  9. java Font 自定义字体
  10. 面试题葵花宝典(脚本与运维篇)