解析Java中未被捕获的异常以及try语句的嵌套使用

Java未被捕获的异常
在你学习在程序中处理异常之前,看一看如果你不处理它们会有什么情况发生是很有好处的。下面的小程序包括一个故意导致被零除错误的表达式。

class Exc0 {
  public static void main(String args[]) {
    int d = 0;
    int a = 42 / d;
  }
}

当Java运行时系统检查到被零除的情况,它构造一个新的异常对象然后抛出该异常。这导致Exc0的执行停止,因为一旦一个异常被抛出,它必须被一个异常处理程序捕获并且被立即处理。该例中,我们没有提供任何我们自己的异常处理程序,所以异常被Java运行时系统的默认处理程序捕获。任何不是被你程序捕获的异常最终都会被该默认处理程序处理。默认处理程序显示一个描述异常的字符串,打印异常发生处的堆栈轨迹并且终止程序。

下面是由标准javaJDK运行时解释器执行该程序所产生的输出:

  java.lang.ArithmeticException: / by zero
  at Exc0.main(Exc0.java:4)

注意,类名Exc0,方法名main,文件名Exc0.java和行数4是怎样被包括在一个简单的堆栈使用轨迹中的。还有,注意抛出的异常类型是Exception的一个名为ArithmeticException的子类,该子类更明确的描述了何种类型的错误方法。本章后面部分将讨论,Java提供多个内置的与可能产生的不同种类运行时错误相匹配的异常类型。

堆栈轨迹将显示导致错误产生的方法调用序列。例如,下面是前面程序的另一个版本,它介绍了相同的错误,但是错误是在main( )方法之外的另一个方法中产生的:

class Exc1 {
  static void subroutine() {
    int d = 0;
    int a = 10 / d;
  }
  public static void main(String args[]) {
    Exc1.subroutine();
  }
}

默认异常处理器的堆栈轨迹结果表明了整个调用栈是怎样显示的:

  java.lang.ArithmeticException: / by zero
  at Exc1.subroutine(Exc1.java:4)
  at Exc1.main(Exc1.java:7)

如你所见,栈底是main的第7行,该行调用了subroutine( )方法。该方法在第4行导致了异常。调用堆栈对于调试来说是很重要的,因为它查明了导致错误的精确的步骤。

Java try语句的嵌套
Try语句可以被嵌套。也就是说,一个try语句可以在另一个try块内部。每次进入try语句,异常的前后关系都会被推入堆栈。如果一个内部的try语句不含特殊异常的catch处理程序,堆栈将弹出,下一个try语句的catch处理程序将检查是否与之匹配。这个过程将继续直到一个catch语句匹配成功,或者是直到所有的嵌套try语句被检查耗尽。如果没有catch语句匹配,Java的运行时系统将处理这个异常。下面是运用嵌套try语句的一个例子:

// An example of nested try statements.
class NestTry {
  public static void main(String args[]) {
    try {
      int a = args.length;
      /* If no command-line args are present,the following statement will generate a divide-by-zero exception. */
      int b = 42 / a;
      System.out.println("a = " + a);
      try { // nested try block
        /* If one command-line arg is used,then a divide-by-zero exception will be generated by the following code. */
        if(a==1) a = a/(a-a); // division by zero
        /* If two command-line args are used,then generate an out-of-bounds exception. */
        if(a==2) {
          int c[] = { 1 };
          c[42] = 99; // generate an out-of-bounds exception
        }
      } catch(ArrayIndexOutOfBoundsException e) {
        System.out.println("Array index out-of-bounds: " + e);
      }
    } catch(ArithmeticException e) {
      System.out.println("Divide by 0: " + e);
    }
  }
}

如你所见,该程序在一个try块中嵌套了另一个try块。程序工作如下:当你在没有命令行参数的情况下执行该程序,外面的try块将产生一个被零除的异常。程序在有一个命令行参数条件下执行,由嵌套的try块产生一个被零除的错误。因为内部的块不匹配这个异常,它将把异常传给外部的try块,在那里异常被处理。如果你在具有两个命令行参数的条件下执行该程序,由内部try块产生一个数组边界异常。下面的结果阐述了每一种情况:

C:\>java NestTry
Divide by 0: java.lang.ArithmeticException: / by zero
C:\>java NestTry One
a = 1
Divide by 0: java.lang.ArithmeticException: / by zero
C:\>java NestTry One Two
a = 2
Array index out-of-bounds: java.lang.ArrayIndexOutOfBoundsException

当有方法调用时,try语句的嵌套可以很隐蔽的发生。例如,你可以把对方法的调用放在一个try块中。在该方法内部,有另一个try语句。这种情况下,方法内部的try仍然是嵌套在外部调用该方法的try块中的。下面是前面例子的修改,嵌套的try块移到了方法nesttry( )的内部:

/* Try statements can be implicitly nested via calls to methods. */
class MethNestTry {
  static void nesttry(int a) {
    try { // nested try block
      /* If one command-line arg is used,then a divide-by-zero exception will be generated by the following code. */
      if(a==1) a = a/(a-a); // division by zero
      /* If two command-line args are used,then generate an out-of-bounds exception. */
      if(a==2) {
        int c[] = { 1 };
        c[42] = 99; // generate an out-of-bounds exception
      }
    } catch(ArrayIndexOutOfBoundsException e) {
      System.out.println("Array index out-of-bounds: " + e);
    }
  }

  public static void main(String args[]) {
    try {
      int a = args.length;
      /* If no command-line args are present,the following statement will generate a divide-by-zero exception. */
      int b = 42 / a;
      System.out.println("a = " + a);
      nesttry(a);
    } catch(ArithmeticException e) {
      System.out.println("Divide by 0: " + e);
    }
  }
}

该程序的输出与前面的例子相同。

(0)

相关推荐

  • 详解Java的内置异常以及创建自定义异常子类的方法

    内置异常子类 在标准包java.lang中,Java定义了若干个异常类.前面的例子曾用到其中一些.这些异常一般是标准类RuntimeException的子类.因为java.lang实际上被所有的Java程序引入,多数从RuntimeException派生的异常都自动可用.而且,它们不需要被包含在任何方法的throws列表中.Java语言中,这被叫做未经检查的异常(unchecked exceptions ).因为编译器不检查它来看一个方法是否处理或抛出了这些异常. java.lang中定义的未经

  • 详解Java异常处理中throw与throws关键字的用法区别

    抛出异常 抛出异常有三种形式,一是throw,一个throws,还有一种系统自动抛异常.下面它们之间的异同. 系统自动抛异常 当程序语句出现一些逻辑错误.主义错误或类型转换错误时,系统会自动抛出异常.如: public static void main(String[] args) { int a = 5, b =0; System.out.println(5/b); //function(); } 系统会自动抛出ArithmeticException异常: Exception in threa

  • Java异常处理之try...catch...语句的使用进阶

    try就像一个网,把try{}里面的代码所抛出的异常都网住,然后把异常交给catch{}里面的代码去处理.最后执行finally之中的代码.无论try中代码有没有异常,也无论catch是否将异常捕获到,finally中的代码都一定会被执行. 虽然 Java 执行时期系统所提供的预设处理器对除错很有用,你通常想要自己处理例外.这样做有两个优点:第一,它让你修正错误.第二,它可以避免程式自动终止.每当错误发生时,如果你的程式就停止而且列印出堆叠追踪,大多数的使用者都会感到很困惑.很幸运,你很容易就能

  • 浅析Java异常处理中断言的使用

    断言的概念 断言用于证明和测试程序的假设,比如"这里的值大于 5". 断言可以在运行时从代码中完全删除,所以对代码的运行速度没有影响. 断言的使用 断言有两种方法: 一种是 assert<<布尔表达式>> : 另一种是 assert<<布尔表达式>> :<<细节描述>>. 如果布尔表达式的值为false , 将抛出AssertionError 异常: 细节描述是AssertionError异常的描述文本使用 jav

  • 解析Java中未被捕获的异常以及try语句的嵌套使用

    Java未被捕获的异常 在你学习在程序中处理异常之前,看一看如果你不处理它们会有什么情况发生是很有好处的.下面的小程序包括一个故意导致被零除错误的表达式. class Exc0 { public static void main(String args[]) { int d = 0; int a = 42 / d; } } 当Java运行时系统检查到被零除的情况,它构造一个新的异常对象然后抛出该异常.这导致Exc0的执行停止,因为一旦一个异常被抛出,它必须被一个异常处理程序捕获并且被立即处理.该

  • 解析java中的condition

    一.condition 介绍及demo Condition是在java 1.5中才出现的,它用来替代传统的Object的wait().notify()实现线程间的协作,相比使用Object的wait().notify(),使用Condition的await().signal()这种方式实现线程间协作更加安全和高效.因此通常来说比较推荐使用Condition,阻塞队列实际上是使用了Condition来模拟线程间协作. Condition是个接口,基本的方法就是await()和signal()方法:

  • 实例解析Java中的构造器初始化

    1.初始化顺序 当Java创建一个对象时,系统先为该对象的所有实例属性分配内存(前提是该类已经被加载过了),接着程序开始对这些实例属性执行初始化,其初始化顺序是:先执行初始化块或声明属性时制定的初始值,再执行构造器里制定的初始值. 在类的内部,变量定义的先后顺序决定了初始化的顺序,即时变量散布于方法定义之间,它们仍就会在任何方法(包括构造器)被调用之前得到初始化. class Window { Window(int maker) { System.out.println("Window(&quo

  • java中double类型运算结果异常的解决方法

    问题: 对两个double类型的值进行运算,有时会出现结果值异常的问题.比如: System.out.println(19.99+20); System.out.println(1.0-0.66); System.out.println(0.033*100); System.out.println(12.3/100); 输出: 39.989999999999995 0.33999999999999997 3.3000000000000003 0.12300000000000001 解决方法: J

  • 详谈Java中BigDecimal的一个除法异常

    如下所示: java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result. 说明遇到除不尽的情况了,需要指定商的小数精度和舍入模式. 比如: a=b.divide(c,2,RoundingMode.HALF_UP); 以上这篇详谈Java中BigDecimal的一个除法异常就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

  • 深入解析Java中反射中的invoke()方法

    先讲一下java中的反射: 反射就是将类别的各个组成部分进行剖析,可以得到每个组成部分,就可以对每一部分进行操作 反射机制应用场景:逆向代码.动态生成类框架等,使用反射机制能够大大的增强程序的扩展性. 反射的基本步骤:首先获得Class对象,然后实例化对象,获得类的属性.方法或者构造函数,最后访问属性.调用方法.调用构造函数创建对象.而invoke()方法就是用来执行指定对象的方法. 在比较复杂的程序或框架中来使用反射技术,可以简化代码提高程序的复用性. 讲的是Method类的invoke()方

  • 解析Java中的static关键字

    一.static关键字使用场景 static关键字主要有以下5个使用场景: 1.1.静态变量 把一个变量声明为静态变量通常基于以下三个目的: 作为共享变量使用 减少对象的创建 保留唯一副本 第一种比较容易理解,由于static变量在内存中只会存在一个副本,所以其可以作为共享变量使用,比如要定义一个全局配置.进行全局计数.如: public class CarConstants { // 全局配置,一般全局配置会和final一起配合使用, 作为共享变量 public static final in

  • 一文解析Java中的方法重写

    目录 1.含义 2.为什么要使用方法重写 3.如何使用方法重写 3.1 基本语法 3.2 具体分析 3.3 方法重写的一些小技巧 1.含义 子类继承父类后,可以在子类中书写一个与父类同名同参的方法,从而实现对父类中同名同参数的方法的覆盖,我们把这一过程叫做方法的重写(override) 2.为什么要使用方法重写 2.1 当父类的方法满足不了子类的需求的时候,需要在子类中对该方法进行重写 2.2 题目与分析 例如存在一个父类Peple,子类Chinese,父类中有一个say()方法,输出人在说话,

  • JAVA中简单的for循环异常踩坑

    目录 引言 踩坑操作 foreach循环剔除方式 下标循环操作 正确方式 迭代器方式 Lambda表达式 Stream流操作 中间对象辅助方式 引言 实际的业务项目开发中,大家应该对从给定的list中剔除不满足条件的元素这个操作不陌生吧? 很多同学可以立刻想出很多种实现的方式,但你想到的这些实现方式都是人畜无害的吗?很多看似正常的操作其实背后是个陷阱,很多新手可能稍不留神就会掉入其中. 倘若不幸踩中: 代码运行时直接抛异常报错,这个算是不幸中的万幸,至少可以及时发现并去解决 代码运行不报错,但是

  • 解析Java中所有错误和异常的父类java.lang.Throwable

    在java语言中,错误类的基类是java.lang.Error,异常类的基类是java.lang.Exception. 1)相同点:java.lang.Error和java.lang.Exception都是java.lang.Throwable的子类,因此java.lang.Error和java.lang.Exception自身及其子类都可以作为throw的使用对象,如:throw new MyError();和throw new MyException();其中,MyError类是java.l

随机推荐