1. JVM如何处理异常

  1. 在程序正常的情况下finally代码块会在try代码块后面运行,如果try代码块抛出了异常,又没有被相应的catch代码块捕获,那么finally代码块会执行完后重新抛出该异常;

  2. 如果异常被catch代码块捕获,则finally代码块在catch代码块之后运行;

  3. 如果catch代码块也抛出了异常,那么finally代码块会运行,然后抛出catch代码块中抛出的异常;

  4. 如果finally代码块也触发了异常,那么中止finally代码块的执行,往外抛出异常;

  5. 异常实例的构造十分昂贵,因为他会逐一访问当前线程的JAVA栈帧,并记录下各种调试信息,包括栈帧所指向的方法名,方法所在的类名、文件名以及在代码的第几行触发异常;

  6. 我们无法通过缓存异常实例,在需要的时候抛出来优化开销,缓存的实例记录的是创建该实例时候的栈信息,无法有效反应出错时候的栈信息,如果使用fillInStackTrace()函数重新更新栈帧信息(主要开销来源),那么仅仅就省了对象创建的开销,那又何必大费周章的缓存实例呢,况且缓存实例还会带来其他问题;

  7. 在编译生成的字节码中,每个方法都带有一个异常表,异常表中的每一个条目都代表了一个异常处理器,由from指针、to指针、target指针、以及所捕获的异常类型组成;这些指针的值是字节码索引,用来定位字节码;

  8. from指针 和 to指针 分别记录了该异常处理器所监控的范围,如try代码块所覆盖的范围,target指针则指向了异常处理器的起始位置,如catch代码块的起始位置;

  9. 当程序出现异常时,Java虚拟机会从上至下遍历异常表中所有的条目,当触发异常的字节码索引值在某个异常处理器监控的范围之内时,Java虚拟机会判断所抛出的异常和该条目想要捕获的异常是否匹配,如果匹配,Java虚拟机会将控制流转移至该条目target指针所指向的字节码;

  10. 如果遍历完所有的条目,仍未找到匹配的异常处理器,则弹出当前方法对应的Java栈帧,并且在调用者中重复上述操作。在最坏的情况下,Java虚拟机需要遍历当前线程Java栈上所有的异常表;

  11. finally代码块的处理相对比较复杂, 目前Java编译器的做法是复制finally代码块的内容到try catch代码块的所有正常以及异常执行路径的出口中;

    11.1 try代码块不抛出异常的正常执行路径出口复制finally代码块的内容;

    11.2 try代码块抛出异常但是被catch代码块捕获并处理的执行出口,复制finally代码块的内容(个人觉得可以跟11.1中共用一份finally代码块,但实际上没有,还没有相通为什么) ;

    11.3 try代码块抛出异常未被catch代码块捕获,或者catch代码块中也抛出了异常,此时finally的处理比较麻烦,编译器生成一条或者多条异常处理器,监控整个try catch代码段的执行,并且捕获的异常对象为任意异常,target指向finally代码块的另一个拷贝,在执行完finally代码块后,重新抛出异常;

  12. 示例代码及编译结果(来自郑雨迪博士的深入理解Java虚拟机):

public class Foo {

private int tryBlock;

private int catchBlock;

private int finallyBlock;

private int methodExit;

public void test() {

try {

  tryBlock = 0;

} catch (Exception e) {

  catchBlock = 1;

} finally {

  finallyBlock = 2;

}

methodExit = 3;

}

}

$ javap -c Foo

public void test();

Code:

  0: aload_0

  1: iconst_0

  2: putfield      #20                // Field tryBlock:I

  5: goto          30

  8: astore_1

  9: aload_0

  10: iconst_1

  11: putfield      #22                // Field catchBlock:I

  14: aload_0

  15: iconst_2

  16: putfield      #24                // Field finallyBlock:I

  19: goto          35

  22: astore_2

  23: aload_0

  24: iconst_2

  25: putfield      #24                // Field finallyBlock:I

  28: aload_2

  29: athrow

  30: aload_0

  31: iconst_2

  32: putfield      #24                // Field finallyBlock:I

  35: aload_0

  36: iconst_3

  37: putfield      #26                // Field methodExit:I

  40: return

Exception table:

  from    to  target type

      0    5    8  Class java/lang/Exception

      0    14    22  any

  1. 如果catch代码块捕获了异常,并且又产生了异常,那么finally代码块捕获并重新抛出的异常将是catch代码块中产生的异常,原异常就丢失了;

  2. Java 7 引入了Supressed的异常来解决13中提到的问题,允许开发人员将一个异常附于另一个异常之上,但语法晦涩,不易使用,try-with-resources语法糖将会自动使用Supressed异常;

  3. 如果finally语句中存在return语句会如何?如果finally中存在return语句,首先,函数的返回值只可能是finally中return的值,不管try catch代码段中是否存在return语句(因为return的对象其实也是一个可以改变的变量,finally中改变了return的对象的值),其次,如果try-catch代码段中产生了未被捕获的异常,那么这个异常将丢失,因为虽然finally生成的异常处理器捕获了异常,但因为在重抛异常之前return了,所以重抛异常语句得不到执行;

开心一下:为什么很多女孩子都有体香,而男的则很少有?因为化妆品、护肤品已经腌入味了!(?纯属调侃)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值