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

作者:goldensun 时间:2022-10-18 20:03:48 

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);
   }
 }
}

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

标签:Java
0
投稿

猜你喜欢

  • 在多线程中调用winform窗体控件的实现方法

    2023-09-13 09:07:43
  • java设计模式学习之工厂方法模式

    2023-10-12 17:19:04
  • java基础入门之IO流

    2022-08-17 00:09:20
  • OpenCV实现反阈值二值化

    2022-06-29 16:02:33
  • Android根据不同身份配置APP对应的不同模块方法

    2023-09-25 05:22:36
  • c# 使用HtmlAgilityPack解析Html

    2021-06-22 11:50:11
  • C#基础入门之值类型和引用类型的区别详析

    2022-02-22 00:14:04
  • Android画板开发之添加背景和保存画板内容为图片

    2022-05-30 04:01:37
  • Android Studio配置Kotlin开发环境详细步骤

    2022-10-09 21:29:35
  • 通过spring注解开发,简单测试单例和多例区别

    2023-11-06 09:18:31
  • 详解Java使用JMH进行基准性能测试

    2021-08-01 12:22:32
  • java验证电话号码的方法

    2023-04-01 21:44:41
  • 深入剖析Android消息机制原理

    2023-09-30 01:57:11
  • servlet之session简介_动力节点Java学院整理

    2023-07-07 00:51:07
  • Android zygote启动流程详解

    2023-09-13 07:44:12
  • Java解析XML的四种方法详解

    2022-07-02 23:39:33
  • 分享一个C#编写简单的聊天程序(详细介绍)

    2023-06-19 03:21:59
  • Spring Boot 项目发布到 Tomcat 服务器的操作步骤

    2023-10-28 09:39:05
  • SpringBoot2整合Drools规则引擎及案例详解

    2021-12-30 05:57:10
  • Android仿微信实现首字母导航条

    2022-07-16 11:14:29
  • asp之家 软件编程 m.aspxhome.com