【知识积累】try-catch-finally+return总结
一、前言
对于找Java相关工作的读者而言,在笔试中肯定免不了遇到try-catch-finally + return的题型,需要面试这清楚返回值,这也是这篇博文产生的由来。本文将从字节码层面来解释为何不同的写法对应的返回结果不相同。当然在实际开发环境下不会这么抠知识点,但是掌握这种分析方法也未尝不可。对于没有此需求的读者大可略过此篇博文。
二、测试
首先进行一个小小的测试,有如下代码
package com.hust.grid.leesf.main; /**
* Created by LEESF on 2016/9/11.
*/
public class FinallyReturnTest {
public static void main(String[] args) {
System.out.println(test1());
System.out.println(test2());
System.out.println(test3());
System.out.println(test4());
System.out.println(test5());
System.out.println(test6());
} /**
* 有异常抛出情况、try、catch、finally均有return语句
* @return
*/
public static int test1() {
int x = 0;
try {
int i = 0;
int j = 1;
int k = j / i;
return x;
} catch (Exception e) {
x = 1;
return x;
} finally {
x = 2;
return x;
}
} /**
* 无异常抛出情况、try、catch、finally均有return语句
* @return
*/
public static int test2() {
int x = 0;
try {
int i = 0;
int j = 1;
return x;
} catch (Exception e) {
x = 1;
return x;
} finally {
x = 2;
return x;
}
} /**
* 有异常抛出,try、catch均有return语句
* @return
*/
public static int test3() {
int x = 0;
try {
int i = 0;
int j = 1;
int k = j / i;
return x;
} catch (Exception e) {
x = 1;
return x;
} finally {
x = 2;
}
}
/**
* 无异常抛出,try、catch均有return语句
* @return
*/
public static int test4() {
int x = 0;
try {
int i = 0;
int j = 1;
return x;
} catch (Exception e) {
x = 1;
return x;
} finally {
x = 2;
}
}
/**
* 无异常抛出,try、方法最后均有return语句
* @return
*/
public static int test5() {
int x = 0;
try {
int i = 0;
int j = 1;
return x;
} catch (Exception e) {
x = 1;
} finally {
x = 2;
} return x;
} /**
* 有异常抛出,try、方法最后均有return语句
* @return
*/
public static int test6() {
int x = 0;
try {
int i = 0;
int j = 1;
int k = j / i;
return x;
} catch (Exception e) {
x = 1;
} finally {
x = 2;
}
return x;
}
}
有兴趣的读者可以自行测试一下,看能否很完整无误的写出正确答案。以上程序的运行结果如下
2
2
1
0
0
2
三、分析
针对上面的结果进行如下的分析。
使用javap -c FinallyReturnTest.class命令查看FinallyReturnTest的字节码,具体如下。
Compiled from "FinallyReturnTest.java"
public class com.hust.grid.leesf.main.FinallyReturnTest {
public com.hust.grid.leesf.main.FinallyReturnTest();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":
()V
4: return public static void main(java.lang.String[]);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/
io/PrintStream;
3: invokestatic #3 // Method test1:()I
6: invokevirtual #4 // Method java/io/PrintStream.printl
n:(I)V
9: getstatic #2 // Field java/lang/System.out:Ljava/
io/PrintStream;
12: invokestatic #5 // Method test2:()I
15: invokevirtual #4 // Method java/io/PrintStream.printl
n:(I)V
18: getstatic #2 // Field java/lang/System.out:Ljava/
io/PrintStream;
21: invokestatic #6 // Method test3:()I
24: invokevirtual #4 // Method java/io/PrintStream.printl
n:(I)V
27: getstatic #2 // Field java/lang/System.out:Ljava/
io/PrintStream;
30: invokestatic #7 // Method test4:()I
33: invokevirtual #4 // Method java/io/PrintStream.printl
n:(I)V
36: getstatic #2 // Field java/lang/System.out:Ljava/
io/PrintStream;
39: invokestatic #8 // Method test5:()I
42: invokevirtual #4 // Method java/io/PrintStream.printl
n:(I)V
45: getstatic #2 // Field java/lang/System.out:Ljava/
io/PrintStream;
48: invokestatic #9 // Method test6:()I
51: invokevirtual #4 // Method java/io/PrintStream.printl
n:(I)V
54: return public static int test1();
Code:
0: iconst_0
1: istore_0
2: iconst_0
3: istore_1
4: iconst_1
5: istore_2
6: iload_2
7: iload_1
8: idiv
9: istore_3
10: iload_0
11: istore 4
13: iconst_2
14: istore_0
15: iload_0
16: ireturn
17: astore_1
18: iconst_1
19: istore_0
20: iload_0
21: istore_2
22: iconst_2
23: istore_0
24: iload_0
25: ireturn
26: astore 5
28: iconst_2
29: istore_0
30: iload_0
31: ireturn
Exception table:
from to target type
2 13 17 Class java/lang/Exception
2 13 26 any
17 22 26 any
26 28 26 any public static int test2();
Code:
0: iconst_0
1: istore_0
2: iconst_0
3: istore_1
4: iconst_1
5: istore_2
6: iload_0
7: istore_3
8: iconst_2
9: istore_0
10: iload_0
11: ireturn
12: astore_1
13: iconst_1
14: istore_0
15: iload_0
16: istore_2
17: iconst_2
18: istore_0
19: iload_0
20: ireturn
21: astore 4
23: iconst_2
24: istore_0
25: iload_0
26: ireturn
Exception table:
from to target type
2 8 12 Class java/lang/Exception
2 8 21 any
12 17 21 any
21 23 21 any public static int test3();
Code:
0: iconst_0
1: istore_0
2: iconst_0
3: istore_1
4: iconst_1
5: istore_2
6: iload_2
7: iload_1
8: idiv
9: istore_3
10: iload_0
11: istore 4
13: iconst_2
14: istore_0
15: iload 4
17: ireturn
18: astore_1
19: iconst_1
20: istore_0
21: iload_0
22: istore_2
23: iconst_2
24: istore_0
25: iload_2
26: ireturn
27: astore 5
29: iconst_2
30: istore_0
31: aload 5
33: athrow
Exception table:
from to target type
2 13 18 Class java/lang/Exception
2 13 27 any
18 23 27 any
27 29 27 any public static int test4();
Code:
0: iconst_0
1: istore_0
2: iconst_0
3: istore_1
4: iconst_1
5: istore_2
6: iload_0
7: istore_3
8: iconst_2
9: istore_0
10: iload_3
11: ireturn
12: astore_1
13: iconst_1
14: istore_0
15: iload_0
16: istore_2
17: iconst_2
18: istore_0
19: iload_2
20: ireturn
21: astore 4
23: iconst_2
24: istore_0
25: aload 4
27: athrow
Exception table:
from to target type
2 8 12 Class java/lang/Exception
2 8 21 any
12 17 21 any
21 23 21 any public static int test5();
Code:
0: iconst_0
1: istore_0
2: iconst_0
3: istore_1
4: iconst_1
5: istore_2
6: iload_0
7: istore_3
8: iconst_2
9: istore_0
10: iload_3
11: ireturn
12: astore_1
13: iconst_1
14: istore_0
15: iconst_2
16: istore_0
17: goto 27
20: astore 4
22: iconst_2
23: istore_0
24: aload 4
26: athrow
27: iload_0
28: ireturn
Exception table:
from to target type
2 8 12 Class java/lang/Exception
2 8 20 any
12 15 20 any
20 22 20 any public static int test6();
Code:
0: iconst_0
1: istore_0
2: iconst_0
3: istore_1
4: iconst_1
5: istore_2
6: iload_2
7: iload_1
8: idiv
9: istore_3
10: iload_0
11: istore 4
13: iconst_2
14: istore_0
15: iload 4
17: ireturn
18: astore_1
19: iconst_1
20: istore_0
21: iconst_2
22: istore_0
23: goto 33
26: astore 5
28: iconst_2
29: istore_0
30: aload 5
32: athrow
33: iload_0
34: ireturn
Exception table:
from to target type
2 13 18 Class java/lang/Exception
2 13 26 any
18 21 26 any
26 28 26 any
}
针对上面的字节码,笔者并不打算从头开始分析,我们着重关心的几个test方法,有兴趣的读者可以参考博主之前写过JVM相关的文章来理解其他内容。传送门:点这里
3.1 test1方法分析
public static int test1();
Code:
0: iconst_0 // 常量0
1: istore_0 // 将常量0存在局部变量表的第一个slot,值得注意的是该方法为静态方法,所以局部变量表的第一个slot并非存储的this引用
2: iconst_0 // 常量0
3: istore_1 // 将常量0存在局部变量表的第二个slot
4: iconst_1 // 常量1
5: istore_2 // 将常量1存在局部变量表的第三个slot
6: iload_2 // 将局部变量表的第三个slot的值(1)放到栈顶
7: iload_1 // 将局部变量表的第二个slot的值(0)放到栈顶
8: idiv // 栈顶元素与次栈顶元素相除,次栈顶元素为除数
9: istore_3 // 将相除的结果保存在局部变量表的第四个slot
10: iload_0 // 将局部变量表的第一个slot的值(0)放到栈顶
11: istore 4 // 将栈顶元素放入局部变量表的第五个slot
13: iconst_2 // 常量2
14: istore_0 // 将常量2存在局部变量表的第一个slot
15: iload_0 // 将局部变量表的第一个slot的值(2)放到栈顶
16: ireturn // 将栈顶的元素返回(返回2)
17: astore_1 // 给catch中定义的Exception e赋值,存在第二个slot中
18: iconst_1 // 常量1
19: istore_0 // 将常量1存在局部变量表的第一个slot
20: iload_0 // 将局部变量表的第一个slot的值(1)放到栈顶
21: istore_2 // 将栈顶元素(1)存在局部变量表的第三个slot中
22: iconst_2 // 常量2
23: istore_0 // 将常量2保存在局部变量表的第一个slot中
24: iload_0 // 将局部变量表的第一个slot的值(2)放到栈顶
25: ireturn // 将栈顶的元素返回(返回2)
26: astore 5 // 给非Exception类型的异常赋值,存在局部变量表的第六个slot中
28: iconst_2 // 常量2
29: istore_0 // 将常量1存在局部变量表的第一个slot
30: iload_0 // 将局部变量表的第一个slot的值(2)放到栈顶
31: ireturn // 将站定的元素返回(返回2)
Exception table: // 异常表
from to target type
2 13 17 Class java/lang/Exception // 当2-13行(对应try语句块)发生属于Exception异常时,则转到17行处理(对应catch语句块)
2 13 26 any // 当2-13行(对应try语句块)发生属于非Exception异常时,则转到26行处理(对应finally语句块)
17 22 26 any // 当17-22行(对应catch语句块)发生异常时,则转到26行处理(对应finally语句块)
26 28 26 any // 当26-28行(对应finally语句块)发生异常时,则转到26行处理(对应finally语句块)
如上图所示,笔者对test1方法的每一条指令进行了详细的说明,可以看到,无论发生异常与否,最后返回的都是2(16行、25行、31行)。对于test2 -> test6方法,均可以依葫芦画瓢进行分析,然后得到返回值。
四、分析总结
无论发生异常与否,finally语句块一定在return之前执行。
以下结论基于如下前提:try的return语句在发生异常语句之后、方法有返回值。
① 当finally语句块中存在return语句时,此时无论是否发生异常,都以该return语句为准,其他的return语句将不起作用。
② 当发生异常时,try存在return语句,catch存在return语句,以catch中的return语句为准,此时在finally语句块中的修改将不起作用。
③ 当发生异常时,try存在return语句,catch不存在return语句,方法在最后存在return语句,以该return语句为准,此时在catch和finally的修改会起作用。
④ 不发生异常时,try存在return语句,不管是catch存在return语句还是方法最后存在return语句,都以try中的return语句为准,此时在catch、finally中的修改将不起作用。
五、总结
在平时要注意知识点的积累,清楚细小知识点背后的原理。也谢谢各位园友的观看~
【知识积累】try-catch-finally+return总结的更多相关文章
- Winform开发几个常用的开发经验及知识积累(一)
本人做Winform开发多年,孜孜不倦,略有小成,其中收集或者自己开发一些常用的东西,基本上在各个项目都能用到的一些开发经验及知识积累,现逐步介绍一些,以飨读者,共同进步. 1.窗口[×]关闭按钮变为 ...
- Asp.net MVC知识积累
一.知识积累 http://yuangang.cnblogs.com/ 跟蓝狐学mvc教程专题目录:http://www.lanhusoft.com/Article/169.html 依赖注入:htt ...
- WinRT知识积累1之读xml数据
前述:这个知识是在Windows8.1或WP8.1中运用Linq to xml获取一个xml文件里的数据.(网上也很多类似的知识,可以借鉴参考) 平台:windows8.1 metro 或者WP8.1 ...
- 【Python】 零碎知识积累 II
[Python] 零碎知识积累 II ■ 函数的参数默认值在函数定义时确定并保存在内存中,调用函数时不会在内存中新开辟一块空间然后用参数默认值重新赋值,而是单纯地引用这个参数原来的地址.这就带来了一个 ...
- try catch finally return之间的关系
一.try catch finally return之间的关系: 正在写dsoFramer的时候,同事突然说面试的时候问的一个问题,catch和return那个先执行,我瞬间迷茫了,然后整理了整理,稍 ...
- 异常 try catch finally return 执行关系 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- try catch finally return运行顺序
首先让我们搞懂两组概念:try catch finally和return 1.try catch finally 首先说try catch, (1)try语句 ,try语句用来包围可能出现异常的代码片 ...
- Java_try,catch,finally return之间的执行顺序
以往认为函数只要执行到return语句便会返回结果并终止,然而这时错误的,因为这存在特例. 掌握下面几条原则就可以完全解决“当try.catch.finally遭遇return”的问题. 原则:1.f ...
- java try catch finally return执行
public static int testBasic(){ int i = 1; try{ i++; System.out.println("try block, i = "+i ...
随机推荐
- 本人提供微软系.NET技术顾问服务,欢迎企业咨询!
背景: 1:目前微软系.NET技术高端人才缺少. 2:企业很难直接招到高端技术人才. 3:本人提供.NET技术顾问,保障你的产品或项目在正确的技术方向. 技术顾问服务 硬服务项: 1:提供技术.决策. ...
- 标准产品+定制开发:专注打造企业OA、智慧政务云平台——山东森普软件,交付率最高的技术型软件公司
一.公司简介山东森普信息技术有限公司(以下简称森普软件)是一家专门致力于移动互联网产品.企业管理软件定制开发的技术型企业.公司总部设在全国五大软件园之一的济南齐鲁软件园.森普SimPro是由Simpl ...
- 关于面试题 Array.indexof() 方法的实现及思考
这是我在面试大公司时碰到的一个笔试题,当时自己云里雾里的胡写了一番,回头也曾思考过,最终没实现也就不了了之了. 昨天看到有网友说面试中也碰到过这个问题,我就重新思考了这个问题的实现方法. 对于想进大公 ...
- PhotoView实现图片随手势的放大缩小的效果
项目需求:在listView的条目中如果有图片,点击条目,实现图片的放大,并且图片可以根据手势来控制图片放大缩小的比例.类似于微信朋友圈中查看好友发布的照片所实现的效果. 思路是这样的:当点击条目的时 ...
- Spring cache简单使用guava cache
Spring cache简单使用 前言 spring有一套和各种缓存的集成方式.类似于sl4j,你可以选择log框架实现,也一样可以实现缓存实现,比如ehcache,guava cache. [TOC ...
- Spring aop应用之实现数据库读写分离
Spring加Mybatis实现MySQL数据库主从读写分离 ,实现的原理是配置了多套数据源,相应的sqlsessionfactory,transactionmanager和事务代理各配置了一套,如果 ...
- [修正] Firemonkey TFrame 存档后,下次载入某些事件连结会消失(但源码还在)
问题:Firemonkey TFrame 存档后,下次载入某些事件连结会消失(但源码还在) 解决:(暂时方法) type TTestFrame = class(TFrame) public const ...
- spider RPC入门指南
本部分将介绍使用spider RPC开发分布式应用的客户端和服务端. spider RPC中间件基于J2SE 8开发,因此需要确保服务器上安装了JDK 8及以上版本,不依赖于任何额外需要独立安装和配置 ...
- 浅谈SQL注入风险 - 一个Login拿下Server
前两天,带着学生们学习了简单的ASP.NET MVC,通过ADO.NET方式连接数据库,实现增删改查. 可能有一部分学生提前预习过,在我写登录SQL的时候,他们鄙视我说:“老师你这SQL有注入,随便都 ...
- python select网络编程详细介绍
刚看了反应堆模式的原理,特意复习了socket编程,本文主要介绍python的基本socket使用和select使用,主要用于了解socket通信过程 一.socket模块 socket - Low- ...