try、catch、finally的使用分析---与 return 相关
看了一篇文章,讲解的是关于java中关于try、catch、finally中一些问题
下面看一个例子(例1),来讲解java里面中try、catch、finally的处理流程
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public class TryCatchFinally { @SuppressWarnings("finally") public static final String test() { String t = ""; try { t = "try"; return t; } catch (Exception e) { // result = "catch"; t = "catch"; return t; } finally { t = "finally"; } } public static void main(String[] args) { System.out.print(TryCatchFinally.test()); }} |
首先程序执行try语句块,把变量t赋值为try,由于没有发现异常,接下来执行finally语句块,把变量t赋值为finally,然后return t,则t的值是finally,最后t的值就是finally,程序结果应该显示finally,但是实际结果为try。为什么会这样,我们不妨先看看这段代码编译出来的class对应的字节码,看虚拟机内部是如何执行的。
我们用javap -verbose TryCatchFinally 来显示目标文件(.class文件)字节码信息
系统运行环境:mac os lion系统 64bit
jdk信息:Java(TM) SE Runtime Environment (build 1.6.0_29-b11-402-11M3527) Java HotSpot(TM) 64-Bit Server VM (build 20.4-b02-402, mixed mode)
编译出来的字节码部分信息,我们只看test方法,其他的先忽略掉

public static final java.lang.String test();
Code:
Stack=, Locals=, Args_size=
: ldc #; //String
: astore_0
: ldc #; //String try
: astore_0
: aload_0
: astore_3
: ldc #; //String finally
: astore_0
: aload_3
: areturn
: astore_1
: ldc #; //String catch
: astore_0
: aload_0
: astore_3
: ldc #; //String finally
: astore_0
: aload_3
: areturn
: astore_2
: ldc #; //String finally
: astore_0
: aload_2
: athrow
Exception table:
from to target type
Class java/lang/Exception any
any
LineNumberTable:
line :
line :
line :
line :
line :
line :
line :
line :
line :
line :
line :
line :
line : LocalVariableTable:
Start Length Slot Name Signature
t Ljava/lang/String;
e Ljava/lang/Exception; StackMapTable: number_of_entries =
frame_type = /* full_frame */
offset_delta =
locals = [ class java/lang/String ]
stack = [ class java/lang/Exception ]
frame_type = /* same_locals_1_stack_item */
stack = [ class java/lang/Throwable ]

首先看LocalVariableTable信息,这里面定义了两个变量 一个是t String类型,一个是e Exception 类型
接下来看Code部分
第[0-2]行,给第0个变量赋值“”,也就是String t="";
第[3-6]行,也就是执行try语句块 赋值语句 ,也就是 t = "try";
第7行,重点是第7行,把第s对应的值"try"付给第三个变量,但是这里面第三个变量并没有定义,这个比较奇怪
第[8-10] 行,对第0个变量进行赋值操作,也就是t="finally"
第[11-12]行,把第三个变量对应的值返回
通过字节码,我们发现,在try语句的return块中,return 返回的引用变量(t 是引用类型)并不是try语句外定义的引用变量t,而是系统重新定义了一个局部引用t’,这个引用指向了引用t对应的值,也就是try ,即使在finally语句中把引用t指向了值finally,因为return的返回引用已经不是t ,所以引用t的对应的值和try语句中的返回值无关了。
下面在看一个例子:(例2)

public class TryCatchFinally {
@SuppressWarnings("finally")
public static final String test() {
String t = "";
try {
t = "try";
return t;
} catch (Exception e) {
// result = "catch";
t = "catch";
return t;
} finally {
t = "finally";
return t;
}
}
public static void main(String[] args) {
System.out.print(TryCatchFinally.test());
}
}

这里稍微修改了 第一段代码,只是在finally语句块里面加入了 一个 return t 的表达式。
按照第一段代码的解释,先进行try{}语句,然后在return之前把当前的t的值try保存到一个变量t',然后执行finally语句块,修改了变量t的值,在返回变量t。
这里面有两个return语句,但是程序到底返回的是try 还是 finally。接下来我们还是看字节码信息

public static final java.lang.String test();
Code:
Stack=, Locals=, Args_size=
: ldc #; //String
: astore_0
: ldc #; //String try
: astore_0
: goto
: astore_1
: ldc #; //String catch
: astore_0
: goto
: pop
: ldc #; //String finally
: astore_0
: aload_0
: areturn
Exception table:
from to target type
Class java/lang/Exception any
LineNumberTable:
line :
line :
line :
line :
line :
line :
line :
line :
line : LocalVariableTable:
Start Length Slot Name Signature
t Ljava/lang/String;
e Ljava/lang/Exception; StackMapTable: number_of_entries =
frame_type = /* full_frame */
offset_delta =
locals = [ class java/lang/String ]
stack = [ class java/lang/Exception ]
frame_type = /* same_locals_1_stack_item */
stack = [ class java/lang/Throwable ]
frame_type = /* same */

这段代码翻译出来的字节码和第一段代码完全不同,还是继续看code属性
第[0-2]行、[3-5]行第一段代码逻辑类似,就是初始化t,把try中的t进行赋值try
第6行,这里面跳转到第17行,[17-19]就是执行finally里面的赋值语句,把变量t赋值为finally,然后返回t对应的值
我们发现try语句中的return语句给忽略。可能jvm认为一个方法里面有两个return语句并没有太大的意义,所以try中的return语句给忽略了,直接起作用的是finally中的return语句,所以这次返回的是finally。
接下来在看看复杂一点的例子:(例3)

public class TryCatchFinally {
@SuppressWarnings("finally")
public static final String test() {
String t = "";
try {
t = "try";
Integer.parseInt(null);
return t;
} catch (Exception e) {
t = "catch";
return t;
} finally {
t = "finally";
// System.out.println(t);
// return t;
}
}
public static void main(String[] args) {
System.out.print(TryCatchFinally.test());
}
}

这里面try语句里面会抛出 java.lang.NumberFormatException,所以程序会先执行catch语句中的逻辑,t赋值为catch,在执行return之前,会把返回值保存到一个临时变量里面t ',执行finally的逻辑,t赋值为finally,但是返回值和t',所以变量t的值和返回值已经没有关系了,返回的是catch
例4:

public class TryCatchFinally {
@SuppressWarnings("finally")
public static final String test() {
String t = "";
try {
t = "try";
Integer.parseInt(null);
return t;
} catch (Exception e) {
t = "catch";
return t;
} finally {
t = "finally";
return t;
}
}
public static void main(String[] args) {
System.out.print(TryCatchFinally.test());
}
}

这个和例2有点类似,由于try语句里面抛出异常,程序转入catch语句块,catch语句在执行return语句之前执行finally,而finally语句有return,则直接执行finally的语句值,返回finally
例5:

public class TryCatchFinally {
@SuppressWarnings("finally")
public static final String test() {
String t = "";
try {
t = "try";
Integer.parseInt(null);
return t;
} catch (Exception e) {
t = "catch";
Integer.parseInt(null);
return t;
} finally {
t = "finally";
//return t;
}
}
public static void main(String[] args) {
System.out.print(TryCatchFinally.test());
}
}

这个例子在catch语句块添加了Integer.parser(null)语句,强制抛出了一个异常。然后finally语句块里面没有return语句。继续分析一下,由于try语句抛出异常,程序进入catch语句块,catch语句块又抛出一个异常,说明catch语句要退出,则执行finally语句块,对t进行赋值。然后catch语句块里面抛出异常。结果是抛出java.lang.NumberFormatException异常
例子6:

public class TryCatchFinally {
@SuppressWarnings("finally")
public static final String test() {
String t = "";
try {
t = "try";
Integer.parseInt(null);
return t;
} catch (Exception e) {
t = "catch";
Integer.parseInt(null);
return t;
} finally {
t = "finally";
return t;
}
}
public static void main(String[] args) {
System.out.print(TryCatchFinally.test());
}
}

这个例子和上面例子中唯一不同的是,这个例子里面finally 语句里面有return语句块。try catch中运行的逻辑和上面例子一样,当catch语句块里面抛出异常之后,进入finally语句快,然后返回t。则程序忽略catch语句块里面抛出的异常信息,直接返回t对应的值 也就是finally。方法不会抛出异常
例子7:

public class TryCatchFinally {
@SuppressWarnings("finally")
public static final String test() {
String t = "";
try {
t = "try";
Integer.parseInt(null);
return t;
} catch (NullPointerException e) {
t = "catch";
return t;
} finally {
t = "finally";
}
}
public static void main(String[] args) {
System.out.print(TryCatchFinally.test());
}
}

这个例子里面catch语句里面catch的是NPE异常,而不是java.lang.NumberFormatException异常,所以不会进入catch语句块,直接进入finally语句块,finally对s赋值之后,由try语句抛出java.lang.NumberFormatException异常。
例子8

public class TryCatchFinally {
@SuppressWarnings("finally")
public static final String test() {
String t = "";
try {
t = "try";
Integer.parseInt(null);
return t;
} catch (NullPointerException e) {
t = "catch";
return t;
} finally {
t = "finally";
return t;
}
}
public static void main(String[] args) {
System.out.print(TryCatchFinally.test());
}
}

和上面的例子中try catch的逻辑相同,try语句执行完成执行finally语句,finally赋值s 并且返回s ,最后程序结果返回finally
例子9:

public class TryCatchFinally {
@SuppressWarnings("finally")
public static final String test() {
String t = "";
try {
t = "try";return t;
} catch (Exception e) {
t = "catch";
return t;
} finally {
t = "finally";
String.valueOf(null);
return t;
}
}
public static void main(String[] args) {
System.out.print(TryCatchFinally.test());
}
}

这个例子中,对finally语句中添加了String.valueOf(null), 强制抛出NPE异常。首先程序执行try语句,在返回执行,执行finally语句块,finally语句抛出NPE异常,整个结果返回NPE异常。
对以上所有的例子进行总结
1 try、catch、finally语句中,在如果try语句有return语句,则返回的之后当前try中变量此时对应的值,此后对变量做任何的修改,都不影响try中return的返回值
2 如果finally块中有return 语句,则返回try或catch中的返回语句忽略。
3 如果finally块中抛出异常,则整个try、catch、finally块中抛出异常
所以使用try、catch、finally语句块中需要注意的是
1 尽量在try或者catch中使用return语句。通过finally块中达到对try或者catch返回值修改是不可行的。
2 finally块中避免使用return语句,因为finally块中如果使用return语句,会显示的消化掉try、catch块中的异常信息,屏蔽了错误的发生
3 finally块中避免再次抛出异常,否则整个包含try语句块的方法回抛出异常,并且会消化掉try、catch块中的异常
参考链接:http://www.cnblogs.com/aigongsi/archive/2012/04/19/2457735.html
http://blog.csdn.net/roholi/article/details/7358265
try、catch、finally的使用分析---与 return 相关的更多相关文章
- 我敢说你不一定完全理解try 块,catch块,finally 块中return的执行顺序
大家好,今天我们来讲一个笔试和面试偶尔都会问到的问题,并且在工作中不知道原理,也会造成滥用. 大家可能都知道,try 块用来捕获异常,catch块是处理try块捕获的异常,finally 块是用来关闭 ...
- 【转】C# 异常处理 throw和throw ex的区别 try catch finally的执行顺序(return)
[转]throw和throw ex的区别 之前,在使用异常捕获语句try...catch...throw语句时,一直没太留意几种用法的区别,前几天调试程序时无意中了解到几种使用方法是有区别的,网上一查 ...
- try catch finally语句块中存在return语句时的执行情况剖析
2种场景 (1) try中有return,finally中没有return(注意会改变返回值的情形);(2) try中有return,finally中有return; 场景代码分析(idea亲测) 场 ...
- try、catch、finally--try块里有return,finally还执行吗?
finally块的作用是,保证无论出现什么情况,finally块里的代码一定会被执行. 由于程序执行return就意味着结束对当前函数的调用并跳出这个函数体,所以任何语句要执行都只能在return之前 ...
- Android WifiDisplay分析一:相关Service的启动
网址:http://www.2cto.com/kf/201404/290996.html 最近在学习Android 4.4上面的WifiDisplay(Miracast)相关的模块,这里先从WifiD ...
- 比较分析与数组相关的sizeof和strlen
首先,我们要清楚sizeof是C/C++中的一个操作符,其作用就是返回一个对象或者类型所占的内存字节数. 而,strlen是一个函数,函数原型为: size_t strlen(const char * ...
- 【GWAS文献】基于GWAS与群体进化分析挖掘大豆相关基因
Resequencing 302 wild and cultivated accessions identifies genes related to domestication and improv ...
- HDFS源码分析:NameNode相关的数据结构
本文主要基于Hadoop1.1.2分析HDFS中的关键数据结构. 1 NameNode 首先从NameNode开始.NameNode的主要数据结构如下: NameNode管理着两张很重要的表: 1) ...
- Android AdapterView 源码分析以及其相关回收机制的分析
忽然,发现,网上的公开资料都是教你怎么继承一个baseadapter,然后重写那几个方法,再调用相关view的 setAdpater()方法, 接着,你的item 就显示在手机屏幕上了.很少有人关注a ...
随机推荐
- Scheme中一些函数在C++里面的实现与吐槽
最终我失败了,这是显而意见,我试图在一个很看重类型是什么的语言中实现无类型操作,事实上,哪怕我实现了基本的cons,car,cdr,list后面的代码也无法写下去.比如说list-n,根据 ...
- Java基础知识强化之网络编程笔记25:Android网络通信之 Future接口介绍(Java程序执行超时)
1. Future接口简介 在Java中,如果需要设定代码执行的最长时间,即超时,可以用Java线程池ExecutorService类配合Future接口来实现. Future接口是Java标准API ...
- Javascript oop深入学习笔记(三)--javascript中类的实现
一.类的实现机制 在javascript中可以使用function关键字来定义一个类.在函数内通过this指针引用的变量或则方法都会成为类的成员. function classDemo(){ var ...
- JSONP与JSON的关系
这篇文章<说说JSON和JSONP,也许你会豁然开朗>写得非常棒,推荐一下 http://kb.cnblogs.com/page/139725/ (大神,对不起,我记录一下,因为你写的真得 ...
- sql 自定义函数--固定格式字符转时间类型
遇到一个德国的客户,他们的时间格式是JJJJ-TT-DD HH:MM:SS,程序按照这个格式将时间插入数据库,但是在sql自带的转换函数convert.cast过程中报错,网上搜了下都说用conver ...
- Linux文件与目录管理之ls的使用
来源:鸟哥的私房菜 查看文件与目录 ls ls [-aAdfFhilnrRSt] 目录名 ls [--color={never,auto,always}] ls [--full-time] 目录名 选 ...
- FTP服务详解
FTP服务 本章机构 简介 File Transfer Protocol(文件传输协议)的英文简称,而中文简称为"文件传输协议".用于Internet上的控制文件的双向传输.同时, ...
- [书目20131114]微软技术丛书•快速软件开发(珍藏版) Rapid Development Taming Wild Software Schedules By Steve McConnell
本文摘自:http://shop.oreilly.com/product/9781556159008.do EFFICIENT DEVELOPMENT Chapter 1 Welcome to Rap ...
- [改善Java代码] 提倡异常的封装
JavaAPI提供的异常都是比较低级别的,低级别是指只有开发人员才能看懂的异常.而对于终端用户来说基本上就是天书,与业务无关,是纯计算机语言的描述. 异常封装的三方面的好处: 1)提高系统的友好性 ...
- 关于String和StringBuffer的使用
java本身提供了n多对象方便我们进行开发,这些对象都是遵从着面向对象思想而出现的,后期再讲就不再讲思想了,而是不断学习这些对象的使用.我们的学习重点已经开始从面向对象思想转移到了面向对象的使用上来了 ...