java中 try catch finally和return联合使用时,代码执行顺序的小细节
代码1测试
public static void main(String[] args) {
aa();
} static int aa() {
try {
int a=4/0;
} catch (Exception e) {
e.printStackTrace();
return 1;
}finally{
System.out.println("finally");
// return 2; return写在这里不规范,不是错误,但有感叹号
}
return 2;
}
输出结果如下:
java.lang.ArithmeticException: / by zero
at com.hcss.cn.Aa1fa.aa(Ja.java:120)
at com.hcss.cn.Aa1fa.main(Ja.java:115)
finally
分析:虽然try中出现了运行异常java.lang.ArithmeticException,被catch捕获到,不管程序是正常运行,还是抛异常,之前都要先调用finally(这里想说下多次执行程序时控制台输出信息顺序会变,是因为e.printStatckTrace和System.out是两个资源,并行执行,但代码2我都用成System.out,多次输出也会偶尔出现乱序,没搞明白,先不管这个小问题了),finally正确使用应该是释放资源,如果finally用了return,这是不规范的写法。
稍微变形的代码2测试(catch的异常类变了)
public static void main(String[] args) {
System.out.println(aa());
} static int aa() {
try {
int a=4/0;
} catch (Error e) {
System.out.println("catch...");
return 1;
}finally{
System.out.println("finally...");
}
//执行完finally,因为没有catch住ArithmeticException异常,导致异常向上层main方法抛出,下边两行system.out没有输出
System.out.println("finally1...");
System.out.println("finally2...");
return 2; }
输出结果如下:
finally...
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.hcss.cn.Aa1fa.aa(Ja.java:120)
at com.hcss.cn.Aa1fa.main(Ja.java:115)
分析:
执行完finally,因为没有catch住ArithmeticException异常,导致异常向上层main方法抛出,下边两行system.out没有输出。
再变形代码3测试(return写在了finally里)
public static void main(String[] args) {
System.out.println(aa());
} static int aa() {
try {
int a=4/0;
} catch (Error e) {
System.out.println("catch...");
return 1;
}finally{
System.out.println("finally...");
return 2; //return写在这里不规范,有感叹号
}
}
输出结果如下:
finally...
2
分析
finally用了return,这是不规范的写法,不应该这么使用,finally中的return使得aa方法丢失了要抛出的异常,相当于aa方法没有向main方法抛出异常,而是只返回一个2。 而后,从网上找到一篇文章,看完又学到一点原理性的小知识(重点是return返回的是一个快照值):
一些准备知识:
首先为了说明白java中finally与return的执行顺序是怎样的这个问题,我们需要做一点准备工作。
java方法是在栈幀中执行,栈幀是线程私有栈的单位,执行方法的线程会为每一个方法分配一小块栈空间来作为该方法执行时的内存空间,栈幀分为三个区域:
1. 操作数栈,用来保存正在执行的表达式中的操作数,数据结构中学习过基于栈的多项式求值算法,操作数栈的作用和这个一样
2. 局部变量区,用来保存方法中使用的变量,包括方法参数,方法内部声明的变量,以及方法中使用到的对象的成员变量或类的成员变量(静态变量),最后两种变量会复制到局部变量区,因此在多线程 环境下,这种变量需要根据需要声明为volatile类型
3. 字节码指令区,这个不用解释了,就是方法中的代码翻译成的指令
return语句:
准备知识讲完了,在本节中我们讲解方法中没有finally语句块的情况下return语句的执行方式。现在我们先看看return语句,return语句的格式如下:
return [expression];
其中expression(表达式)是可选的,因为有些方法没有返回值,所以return后面也就没有表达式,或者可以看做是空的表达式。
我们知道return语句的作用可以结束方法并返回一个值,那么他返回的是哪里的值呢?返回的是return指令执行的时刻,操作数栈顶的值,不管expression是一个怎样的表达式,究竟做了些什么工作,对于return指令来说都不重要,他只负责把操作数栈顶的值返回。
而return expression是分成两部分执行的:
执行:expression;
执行:return指令;
例如:return x+y;
这句代码先执行x+y,再执行return;首先执行将x以及y从局部变量区复制到操作数栈顶的指令,然后执行加法指令,这个时候结果x+y的值会保存在操作数栈的栈顶,最后执行return指令,返回操作数栈顶的值。
对于return x;先执行x,x也是一个表达式,这个表达式只有一个操作数,会执行将变量x从局部变量区复制到操作数栈顶的指令,然后执行return,返回操作数栈顶的值。因此return x实际返回的是return指令执行时,x在操作数栈顶的一个快照或者叫副本,而不是x这个值。
finally语句块:
如果方法中有finally语句块,那么return语句又是如何执行的呢?
例如下面这段代码:
try{
return expression;
}finally{
do some work;
}
首先我们知道,finally语句是一定会执行,但他们的执行顺序是怎么样的呢?他们的执行顺序如下:
1、执行:expression,计算该表达式,结果保存在操作数栈顶;
2、执行:操作数栈顶值(expression的结果)复制到局部变量区作为返回值;
3、执行:finally语句块中的代码;
4、执行:将第2步复制到局部变量区的返回值又复制回操作数栈顶;
5、执行:return指令,返回操作数栈顶的值;
我们可以看到,在第一步执行完毕后,整个方法的返回值就已经确定了,由于还要执行finally代码块,因此程序会将返回值暂存在局部变量区,腾出操作数栈用来执行finally语句块中代码,等finally执行完毕,再将暂存的返回值又复制回操作数栈顶。所以无论finally语句块中执行了什么操作,都无法影响返回值,所以试图在finally语句块中修改返回值是徒劳的。因此,finally语句块设计出来的目的只是为了让方法执行一些重要的收尾工作,而不是用来计算返回值的。
如果还有不懂的话可以看看示例代码
public class FinallyDemo {
public int testMethod(String _int,String _className){
int x = 1;
try{
Integer.valueOf(_int);
Class.forName(_className);
//如果上面两句代码没有发生异常,对于return x这句代码,程序会先计算表达式x
//即将x从局部变量区复制到操作数栈顶,结果就是操作数栈顶的值,也就是x的值,为1
//然后将操作数栈顶的值复制到局部变量区(假设这个复制到局部变量区的值叫returnvalue),再执行finally代码块,在finally代码块
//中,x的值被修改为3(即局部变量区中的x值),finally执行完,程序又将returnvalue复制到操作数栈顶,然后执行return指令,返回
//操作数栈顶的值,最终返回值是1
return x;
}catch(ClassNotFoundException e){
//同样发生了ClassNotFoundException,x的值被修改成2
//因此在catch中的return x语句中定义了返回值大小为2,所以最终返回的是2
x = 2;
return x;
}finally{
//这句代码一定会执行的,这里的代码执行结束后才会结束方法并返回值,因此在finally语句修改x不会影响返回值,因为返回值在return 后面的
//表达式执行完就已经确定了,他是x的快照,而不是x
x = 3;
}
}
public static void main(String [] args){
try{
FinallyDemo demo = new FinallyDemo();
int i_1 = demo.testMethod("123123", "expert.in.java.lang.CalendarDemo");
System.out.println(i_1);//结果为1
int i_2 = demo.testMethod("123123", "com.edu.cn.qj.MyClass");
System.out.println(i_2);//结果为2
int i_3 = demo.testMethod("dsadf", "expert.in.java.lang.CalendarDemo");
System.out.println(i_3);//没有返回值,会抛出异常
}finally{
}
}
}
---------------------
作者:qj19842011
来源:CSDN
原文:https://blog.csdn.net/qj19842011/article/details/45675057
版权声明:本文为博主原创文章,转载请附上博文链接!
java中 try catch finally和return联合使用时,代码执行顺序的小细节的更多相关文章
- Java 中无返回值的方法在使用时应该注意的问题
Java 中的方法是形态多样的.无返回值的方法在使用时应该规避哪些问题呢? 一.不可以打印调用或是赋值调用,只能是单独调用(非常重要): 二.返回值没有,不代表参数就没有: 三.不能return一个具 ...
- Java中继承时静态块,构造块,构造函数的执行顺序
public class Father { static { System.out.println("Father静态块"); } { System.out.println(&qu ...
- 【转】Java中try catch finally语句中含有return语句的执行情况(总结版)
Java中try catch finally语句中含有return语句的执行情况(总结版) 有一点可以肯定,finally块中的内容会先于try中的return语句执行,如果finall语句块中也有r ...
- java中try{}catch{}和finally{}的执行顺序问题
今天我给大家讲解一下java的的错误和异常处理机制以及相关异常的执行顺序问题.如有不足的地方,欢迎批评指正~ 1.首相简单介绍一下java中的错误(Error)和异常(Exception) 错误和异 ...
- Java中try,catch,finally的用法
Java中try,catch,finally的用法,以前感觉还算熟悉,但看到一篇博文才有更深点的理解,总结网友博客如下. Java异常处理的组合方式: 1.try+catch 运行流程:运行到try ...
- java中break、continue、return作用
java中break.continue.return作用 0.首先要明确:break和continue是作用对象是循环体:而return的作用对象是方法 break:在执行完本次循环后,跳出所在的循环 ...
- 关于JAVA中事件分发和监听机制实现的代码实例-绝对原创实用
http://blog.csdn.net/5iasp/article/details/37054171 文章标题:关于JAVA中事件分发和监听机制实现的代码实例 文章地址: http://blog.c ...
- 当C#中带有return的TryCatch代码遇到Finally时代码执行顺序
编写的代码最怕出现的情况是运行中有错误出现,但是无法定位错误代码位置.综合<C#4.0图解教程>,总结如下: TryCatchFinally用到的最多的是TryCatch,Catch可以把 ...
- java中如何把图片转换成二进制流的代码
在学习期间,把开发过程经常用到的一些代码段做个备份,下边代码内容是关于java中如何把图片转换成二进制流的代码,应该能对各朋友也有用处. public byte[] SetImageToByteArr ...
随机推荐
- 基于flask+gunicorn+nginx来部署web App
基于flask+gunicorn&&nginx来部署web App WSGI协议 Web框架致力于如何生成HTML代码,而Web服务器用于处理和响应HTTP请求.Web框架和Web服务 ...
- Codeforces 279D The Minimum Number of Variables 状压dp
The Minimum Number of Variables 我们定义dp[ i ][ mask ]表示是否存在 处理完前 i 个a, b中存者 a存在的状态是mask 的情况. 然后用sosdp处 ...
- UOJ#348. 【WC2018】州区划分
原文链接www.cnblogs.com/zhouzhendong/p/UOJ348.html 前言 第一次知道子集卷积可以自己卷自己. 题解 这是一道子集卷积模板题. 设 $sum[S]$ 表示点集 ...
- pycharm的list中append的应用
li = [11,22,33,44] li.append(5) print(li) #输出结果 [11,22,33,44,5] #后面可加字母,列表等字符串
- HDU - 1827 Summer Holiday (强连通)
<题目链接> 题目大意: 听说lcy帮大家预定了新马泰7日游,Wiskey真是高兴的夜不能寐啊,他想着得快点把这消息告诉大家,虽然他手上有所有人的联系方式,但是一个一个联系过去实在太耗时间 ...
- mxGraph绘制流程图
代码如下: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w ...
- BZOJ.4137.[FJOI2015]火星商店问题(线段树分治 可持久化Trie)
BZOJ 洛谷 一直觉得自己非常zz呢.现在看来是真的=-= 注意题意描述有点问题,可以看BZOJ/洛谷讨论. 每个询问有两个限制区间,一是时间限制\([t-d+1,t]\),二是物品限制\([L,R ...
- Windows10用fiddler抓包Android应用(解决手机设置代理后无法上网,设置只抓app包)
1.环境准备 1.电脑上安装fiddler 2.手机和电脑在同一个局域网内 2.设置 1.fiddler>Tools>Fiddler Options>Connections 勾选Al ...
- php位运算
php位运算 /** * 位运算 */ echo "<pre>"; $aa = $a&$b; //按位与,相同位都为1时为1,其他都为0; echo " ...
- JavaScript字符串与数组方法整理
字符串(String)的方法: 代码后面的都是返回值 var str = "atusdgafsvg"; var str1 = "123456789"; var ...