JVM中的异常处理

标签: jvm 异常处理 | 发表时间:2014-06-02 03:54 | 作者:Rolandz
出处:http://www.blogjava.net/

欢迎来到“ Under The Hood”第六期。本期我们介绍 JVM处理异常的方式,包括如何抛出和捕获异常及相关的字节码指令。但本文不会讨论finally子句,这是下期的主题。你可能需要阅读 往期的文章才能更好的理解本文。

异常处理

在程序运行时,异常让你可以平滑的处理意外状况。为了演示JVM处理异常的方式,考虑NitPickyMath类,它提供对整数进行加,减,乘,除以及取余的操作。

NitPickyMath提供的这些操作和Java语言的“+”,“-”,“*”,“/”和“%”是一样的,除了NitPickyMath中的方法在以下情况下会抛出检查型(checked)异常:上溢出,下溢出以及被0除。0做除数时,JVM会抛出ArithmeticException异常,但是上溢出和下溢出不会引发任何异常。NitPickyMath中抛出异常的方法定义如下:

  1. class OverflowException extends Exception {
  2. }
  3. class UnderflowException extends Exception {
  4. }
  5. class DivideByZeroException extends Exception {
  6. }

NitPickyMath类中的remainder()方法就是一个抛出和捕获异常的简单方法。

  1. static int remainder(int dividend, int divisor)
  2.     throws DivideByZeroException {
  3.     try {
  4.         return dividend % divisor;
  5.     }
  6.     catch (ArithmeticException e) {
  7.         throw new DivideByZeroException();
  8.     }
  9. }

remainder()方法,只是简单的对当作参数传递进来的2个整数进行取余操作。如果取余操作的除数是0,会引发ArithmeticException异常。remainder()方法捕获这个异常,并重新抛出DivideByZeroException异常。

DivideByZeroException和ArithmeticException的区别是,DivideByZeroException是检查型(checked)异常,而ArithmeticException是非检查(unchecked)型异常。由于ArithmeticException是非检查型异常,一个方法就算会抛出该异常,也不必在其throw子句中声明它。任何Error或RuntimeException异常的子类异常都是非检查型异常。(ArithmeticException就是RuntimeException的子类。)通过捕获ArithmeticException和抛出DivideByZeroException,remainder()方法强迫它的调用者去处理除数为0的可能性,要么捕获它,要么在其throw子句中声明DivideByZeroException异常。这是因为,像DivideByZeroException这种在方法中抛出的检查型异常,要么在方法中捕获,要么在其throw子句中声明,二者必选其一。而像ArithmeticException这种非检查型异常,就不需要去显式捕获和声明。

javac为remainder()方法生成的字节码序列如下:

  1. // The main bytecode sequence for remainder:
  2. 0 iload_0               // Push local variable 0 (arg passed as divisor)
  3. 1 iload_1               // Push local variable 1 (arg passed as dividend)
  4. 2 irem                  // Pop divisor, pop dividend, push remainder
  5. 3 ireturn               // Return int on top of stack (the remainder)
  6. // The bytecode sequence for the catch (ArithmeticException) clause:
  7. 4 pop                   // Pop the reference to the ArithmeticException
  8.                         // because it is not used by this catch clause.
  9. 5 new #5 < Class DivideByZeroException >
  10.                         // Create and push reference to new object of class
  11.                         // DivideByZeroException.
  12. 8 dup                   // Duplicate the reference to the new
  13.                         // object on the top of the stack because it
  14.                         // must be both initialized
  15.                         // and thrown. The initialization will consume
  16.                         // the copy of the reference created by the dup.
  17. 9 invokenonvirtual #9 < Method DivideByZeroException.< init >()V >
  18.                         // Call the constructor for the DivideByZeroException
  19.                         // to initialize it. This instruction
  20.                         // will pop the top reference to the object.
  21. 12 athrow               // Pop the reference to a Throwable object, in this
  22.                         // case the DivideByZeroException,
  23.                         // and throw the exception.

remainder()方法的字节码有2个单独的部分。第一部分是该方法的正常执行路径,这部分从第0行开始,到第3行结束。第二部分是从第4行开始,到12行结束的catch子句。

主字节码序列中的irem指令可能会抛出ArithmeticException异常。如果异常发生了,JVM通过在异常表中查找匹配的异常,它会知道要跳转到相应的异常处理的catch子句的字节码序列部分。每个捕获异常的方法,都跟类文件中与方法字节码一起交付的异常表关联。每一个捕获异常的try块,都是异常表中的一行。每行4条信息:开始行号(from)和结束行号(to),要跳转的字节码序列行号(target),被捕获的异常类的常量池索引(type)。remainder()方法的异常表如下所示:

FROM
TO
TARGET
TYPE
0 4 4 < Class java.lang.ArithmeticException >

上面的异常表表明,行号1到3范围内,ArithmeticException将被捕获。异常表中的“to”下面的结束行号始终比异常捕获的最大行号大1,上表中,结束行号为4,而异常捕获的最大行号是3。行号0到3的字节码序列对应remainder()方法中的try块。“target”列中,是行0到3的字节码发生ArithmeticException异常时要跳转到的目标行号。

如果方法执行过程中产生了异常,JVM会在异常表中查找匹配行。异常表中的匹配行要符合下面的条件:当前pc寄存器的值要在该行的表示范围之内,[from, to),且产生的异常是该行所指定的异常类或其子类。JVM按从上到下的次序查找异常表。当找到了第一个匹配行,JVM把pc寄存器设为新的跳转行号,从此行继续往下执行。如果找不到匹配行,JVM弹出当前栈帧,并重新抛出同一个异常。当JVM弹出当前栈帧时,它会终止当前方法的执行,返回到调用该方法的上一个方法那里。这时,在上一个方法里,并不会继续正常的执行过程,而是抛出同样的异常,促使JVM重新查找该方法的异常表。

Java程序员可以用throw语句抛出像remainder()方法的catch子句中的异常,DivideByZeroException。下表列出了抛出异常的字节码:

OPCODE
OPERAND(S)
DESCRIPTION
athrow (none) pops Throwable object reference, throws the exception

athrow指令把栈顶元素弹出,该元素必须是Throwable的子类或其自身的对象引用,而抛出的异常类型由栈顶弹出的对象引用所指明。

本文译自: How the Java virtual machine handles exceptions

本文出自: 码农合作社 》 JVM中的异常处理,转载请注明。



Rolandz 2014-06-02 03:54 发表评论

相关 [jvm 异常处理] 推荐:

JVM中的异常处理

- - BlogJava-首页技术区
欢迎来到“ Under The Hood”第六期. 本期我们介绍 JVM处理异常的方式,包括如何抛出和捕获异常及相关的字节码指令. 但本文不会讨论finally子句,这是下期的主题. 你可能需要阅读 往期的文章才能更好的理解本文. 在程序运行时,异常让你可以平滑的处理意外状况. 为了演示JVM处理异常的方式,考虑NitPickyMath类,它提供对整数进行加,减,乘,除以及取余的操作.

Oracle 异常处理

- - 编程语言 - ITeye博客
使用RAISE_APPLICATION_ERROR存储过程. ============================================================ */ --演示该存储过程 BEGIN. RAISE_APPLICATION_ERROR(-20000, 'Account past due.');-- explicitly raise exception END; --创建子程序 CREATE OR REPLACE PROCEDURE account_status (.

spring mvc 异常处理(转)

- - 编程语言 - ITeye博客
链接:http://gaojiewyh.iteye.com/blog/1297746 (附源码). 链接:http://zywang.iteye.com/blog/983801 . 链接:http://www.cnblogs.com/xguo/p/3163519.html . 链接:http://fuliang.iteye.com/blog/947191 .

Oracle异常处理概念

- - Oracle - 数据库 - ITeye博客
5.1.1 预定义的异常处理. 5.1.2 非预定义的异常处理. 5.1.3 用户自定义的异常处理. 5.1.4  用户定义的异常处理. 5.2.1 在执行部分引发异常错误. 5.2.2 在声明部分引发异常错误. 5.3 异常错误处理编程. 5.4  在 PL/SQL 中使用 SQLCODE, SQLERRM异常处理函数.

Java异常处理策略

- - 研发管理 - ITeye博客
任务与预先设定的规则不相符的情况都可以称之为异常. 但凡业务逻辑操作,都会划定一些边界或规则,但是往往事与愿违,总会有调皮鬼来挑战系统的健壮性. 用户并不都是知道潜规则的,比如用户的银行账户中只有100块钱,但是用户不查询就直接取200块. 码农有时候太过自信了,比如你在编写文件下载功能时忽略了文件有可能不存在这个分支流程.

【javaScript基础】异常处理

- - CSDN博客Web前端推荐文章
         理解异常在javaScript面向对象编程是非常重要的,异常是一种非常强大的处理错误的方式.          首先我们来看一个有问题的代码:. 在以上这个例子中,访问一个不存在的变量,在这种情况下,程序会怎么处理. 很早以前的处理方式就是程序直接崩溃死掉,所以我们不能容忍这种处理方式,需要有办法来处理.

spring3.0异常处理进阶

- - Web前端 - ITeye博客
spring3.0开发不可避免要遇到异常处理,如果只有jsp请求能捕获到异常,是不足够的, 有时候AJAX返回json数据时遇到异常. 这时候默认的处理方式不能满足了, 需要自定义的方式支持同步和ajax异步异常处理.  或许大家都知道spring3的异常处理方法有:. 1   以配置文件的方式进行异常管理.

异常处理的最佳实践

- - 博客 - 伯乐在线
译者注:这是一篇2003年的文章,因为时间久远,可能有些观点已经过时,但里面讨论的大部分方法如今仍能适用. 如若有其他好的错误处理的方法,欢迎留言. 异常处理的关键就在于知道何时处理异常以及如何使用异常. 这篇文章,我会提到一些最佳的异常处理方法. 我也会总结checked exception的用法.

Java异常处理的陋习展播

- - 博客 - 伯乐在线
注:本文来自志军(@ _Zhijun )在微博推荐的一篇转载于2007年09月27的旧文,他说“没法找到原作者”. 的确,我也花了半个多小时在找原作者. 先是找到了一个标注“2005年6月18日转字Java研究组织”的文章(“Java研究组织”的域名已过期),后来找到是大连理工大学碧海青天BBS上一个发于的2003年5月中旬的 合集帖子,其中提到一条来自 CSDN 的链接,可惜该链接已挂,否则应该能找到作者的.

高效的异常处理框架(转)

- - 企业架构 - ITeye博客
原文:https://www.sunwei.org/archives/196. 摘要:本文从Java异常最基本的概念、语法开始讲述了Java异常处理的基本知识,分析了Java异常体系结构,对比Spring的异常处理框架,阐述了异常处理的基本原则. 并且作者提出了自己处理一个大型应用系统异常的思想,并通过设计一个异常处理的框架来论述此思想.