为什么80%的码农都做不了架构师?>>>   

看了一位博友的一片文章,讲解的是关于java中关于try、catch、finally中一些问题

下面看一个例子(例1),来讲解java里面中try、catch、finally的处理流程

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=1, Locals=4, Args_size=00:    ldc    #16; //String 2:    astore_03:    ldc    #18; //String try5:    astore_06:    aload_07:    astore_38:    ldc    #20; //String finally10:    astore_011:    aload_312:    areturn13:    astore_114:    ldc    #22; //String catch16:    astore_017:    aload_018:    astore_319:    ldc    #20; //String finally21:    astore_022:    aload_323:    areturn24:    astore_225:    ldc    #20; //String finally27:    astore_028:    aload_229:    athrowException table:from   to  target type8    13   Class java/lang/Exception8    24   any19    24   anyLineNumberTable: line 5: 0line 8: 3line 9: 6line 15: 8line 9: 11line 10: 13line 12: 14line 13: 17line 15: 19line 13: 22line 14: 24line 15: 25line 16: 28LocalVariableTable: Start  Length  Slot  Name   Signature27      0    t       Ljava/lang/String;10      1    e       Ljava/lang/Exception;StackMapTable: number_of_entries = 2frame_type = 255 /* full_frame */offset_delta = 13locals = [ class java/lang/String ]stack = [ class java/lang/Exception ]frame_type = 74 /* 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=1, Locals=2, Args_size=00:    ldc    #16; //String 2:    astore_03:    ldc    #18; //String try5:    astore_06:    goto    179:    astore_110:    ldc    #20; //String catch12:    astore_013:    goto    1716:    pop17:    ldc    #22; //String finally19:    astore_020:    aload_021:    areturnException table:from   to  target type9     9   Class java/lang/Exception16    16   anyLineNumberTable: line 5: 0line 8: 3line 9: 6line 10: 9line 12: 10line 13: 13line 14: 16line 15: 17line 16: 20LocalVariableTable: Start  Length  Slot  Name   Signature19      0    t       Ljava/lang/String;6      1    e       Ljava/lang/Exception;StackMapTable: number_of_entries = 3frame_type = 255 /* full_frame */offset_delta = 9locals = [ class java/lang/String ]stack = [ class java/lang/Exception ]frame_type = 70 /* same_locals_1_stack_item */stack = [ class java/lang/Throwable ]frame_type = 0 /* 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块中的异常

转载于:https://my.oschina.net/adan1/blog/159587

java中关于try、catch、finally中的细节分析相关推荐

  1. java线程创建过程_Java创建线程的细节分析

    转载:http://shmilyaw-hotmail-com.iteye.com/blog/1880902 前言 关于线程创建的问题,可以说是老生常谈了.在刚开始学习Thread的时候基本上都会接触到 ...

  2. async/await 中的 try/catch

    async/await 中的try/catch es6中的async是异步编程的终极解决方案,近期学习了一下,相对于 generator 来说,具有更好的特性:内置执行器.更好的语义.更好的适用性,需 ...

  3. Java 中关于 try、catch、finally 中的细节分析

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:God Is Coder https://www.cnblo ...

  4. java try catch_Java中关于try、catch、finally中的细节分析

    作者:God Is Coder https://www.cnblogs.com/aigongsi 看了一位博友的一篇文章,讲解的是关于java中关于try.catch.finally中一些问题 下面看 ...

  5. java如何捕获多个异常_是否可以在单个catch块中捕获多个Java异常?

    例外是程序执行期间发生的问题(运行时错误).发生异常时,程序会突然终止,并且生成异常的行之后的代码将永远不会执行. 代码中有多个异常 在Java 7之前,只要我们有一个可能会生成多个异常的代码,并且如 ...

  6. java中try 与catch的使用

     (2011-10-08 17:08:43) 转载▼ 标签: 杂谈 分类: Java try{ //代码区 }catch(Exception e){ //异常处理 } 代码区如果有错误,就会返回所写异 ...

  7. java try的用法_Java中try、catch的使用方法

    Java中有两种处理异常的方式,分别是用throws抛出异常.用try.catch捕获异常. try-catch 在Java try-catch语句的语法格式: try{ //代码块 }catch(E ...

  8. [转载]java中try 与catch的使用

    留着以后看 原文地址:java中try 与catch的使用作者:碌碌如玉 try{ //代码区 }catch(Exception e){ //异常处理 } 代码区如果有错误,就会返回所写异常的处理. ...

  9. 我可以在同一个catch子句中捕获多个Java异常吗?

    本文翻译自:Can I catch multiple Java exceptions in the same catch clause? In Java, I want to do something ...

最新文章

  1. 程序猿必备的硬核知识,你知道哪些?
  2. Hadoop源代码eclipse编译指南
  3. “老四”网易云音乐急上市:一个音乐APP的终点站?
  4. 一个TextView使用不同的颜色
  5. 演练-使用xapth与lxml库进行操作-0223
  6. 机器学习算法(1)——贝叶斯估计与极大似然估计与EM算法之间的联系
  7. Shiro Shiro Web Support and EnvironmentLoaderListener
  8. c#和javascript分别轻松实现计算24点
  9. 三个linux系统共存,修改默认启动
  10. 二分图最大权匹配【KM算法 BFS优化下的真正的O(N3)的KM算法】【KM算法模板】
  11. 一张图,详解大数据技术架构
  12. pdf打印机怎么把PDF文件打印成JPG
  13. 【3D建模】2020最好用的3款3D建模软件!新手入门必备建模软件!
  14. 山东科技大学计算机学院陈卓艳,转发教务部表彰大学生学习竞赛获奖单位和个人通知...
  15. Kepware通过网络配置三菱FX5U型号PLC的方法
  16. ps aux 进程状态为 I (大写i)
  17. UG二次开发-加工篇:获取刀具的直径,总长,刃长等
  18. 人工智能医疗检测:微核细胞情况自动检出率可达90%
  19. IE6/7常用的hack
  20. wps计算机一级考试,计算机等级考试一级WPS-Office考试大纲

热门文章

  1. iOS开发如何避免安全隐患
  2. layUI 实现自定义弹窗
  3. 《走进git时代系列一》 你该怎么玩?
  4. 零代码实战 SharePoint 2013 BCS:三、实干篇
  5. CoffeeScript和Sass提高Web开发效率
  6. 计算机专业毕业文案,我们毕业啦!|今天,没有文案
  7. NASM中SECTION的概念
  8. spring入门(12)-spring与hibernate整合完成增删改查的操作(继承HibernateDaoSupport调用hibernateTemplate类)
  9. java基础之堆、栈、方法区 继承 多态
  10. golang中的new和make的区别