Java 异常的捕获与处理详解 (一)

一,异常的产生(Exception)

  异常是程序之中导致程序中断的一种指令流,异常一旦出现并且没有进行合理处理的话,那么程序就会中断执行。

  An exception is a flow of instruction that causes a program to interrupt in a propram. If an exception occurs and is not properly handled, the program is interrupted.

  (1)不产生异常的程序: the program without any exceptions 

1 public class Test {
2     public static void main(String args[]) {
3         System.out.println("1、除法计算开始。");
4         int result = 10 / 2;
5         System.out.println("2、除法计算结果:" + result);
6         System.out.println("3、除法计算结束。");
7     }
8 }

  运行结果:result of operation

1 1、除法计算开始。
2 2、除法计算结果:5
3 3、除法计算结束。

  (2)产生异常的程序, the program with an exception

1 public class Test {
2     public static void main(String args[]) {
3         System.out.println("1、除法计算开始。");
4         int result = 10 / 0; // 会出现错误
5         System.out.println("2、除法计算结果:" + result);
6         System.out.println("3、除法计算结束。");
7     }
8 }

  运行结果:result of operation

1、除法计算开始。Exception in thread "main"
java.lang.ArithmeticException: / by zero
    at Test.main(Test.java:4)  

  一旦产生异常,我们发现产生异常的语句以及以后的语句将不再执行,默认情况下是进行异常信息输出,而后自动结束程序的执行。

  Once an exception is generated, we find that the statement that produced the exception and the subsequent statement will no longer be executed, by default the exception information output, and then the execution of the automatic termination program.

  现在我们要做是:即使异常出现了我们也要让程序正确地执行完毕。

二,异常处理

  如果希望程序出现异常之后程序依然可以正常的完成的话,那么就可以使用如下的格式进行异常的处理:

1 try {
2          可能出现异常的语句 ;
3 } [ catch (异常类型 异常对象) {
4          处理异常 ;
5 } catch (异常类型 异常对象) {
6          处理异常 ;
7 } ... ] [finally {
8          不管是否出现异常,都执行此代码 ;
9 }]

  现在,使用以上的操作处理异常处理前面除法于是出现的异常:

 1 public class Test {
 2     public static void main(String args[]) {
 3         System.out.println("1、除法计算开始。");
 4         try {
 5             int result = 10 / 0; // 异常
 6             System.out.println("2、除法计算结果:" + result); // 之前语句有异常,此语句不再执行
 7         } catch (ArithmeticException e) {
 8             System.out.println(e); // 异常处理:输出错误信息,java.lang.ArithmeticException:/ by zero
 9         }
10         System.out.println("3、除法计算结束。");
11     }
12 }

  运行结果:

1 1、除法计算开始。
2 java.lang.ArithmeticException: / by zero
3 3、除法计算结束。

  可以发现,加入了异常处理之后,程序中即使有了异常,程序也可以正常的执行完毕,但是异常处理时的错误输出信息和之前相比,出错的信息不明确了,那么为了让错误的信息更加的完整,一般都会调用printStackTrace()方法进行异常信息的打印,这个方法打印的异常信息是最完整的:

  

public class Test {
    public static void main(String args[]) {
        System.out.println("1、除法计算开始。");
        try {
            int result = 10 / 0; // 异常
            System.out.println("2、除法计算结果:" + result); // 之前语句有异常,此语句不再执行
        } catch (ArithmeticException e) {
            e.printStackTrace(); // 异常处理:输出错误信息
        }
        System.out.println("3、除法计算结束。");
    }
}

  运行结果:

1、除法计算开始。
java.lang.ArithmeticException: / by zero
    at Test.main(Test.java:5)
3、除法计算结束。

  此时发现,打印的信息是很完整的。

  在此处就多说一点,你重复几次地去执行上面的程序的时候,你会发现以上信息输出的顺序有时候会有变动,例如下面这样

1 1,除法计算开始
2 3,除法计算结束
3 java.lang.ArithmeticException: / by zero
4     at com.nokia.test1.exception_1.main(exception_1.java:10)

  个人理解是:当程序调用 e.printStackTrace(); 方法的时候,它也在继续往下执行,这时候应该是两个进程在执行着。(如有错误欢迎指正!!!

  除了try…catch格式处理异常外,还可以使用try…catch..finally:

public class Test {
    public static void main(String args[]) {
        System.out.println("1、除法计算开始。");
        try {
            int result = 10 / 1;
            System.out.println("2、除法计算结果:" + result);
        } catch (ArithmeticException e) {
            e.printStackTrace();
        } finally {
            System.out.println("不管是否出现异常都执行");
        }
        System.out.println("3、除法计算结束。");
    }
}

  运行结果:

1 1、除法计算开始。
2 2、除法计算结果:10
3 不管是否出现异常都执行
4 3、除法计算结束。

  但是,对于之前的程序又有了问题:现在执行数学计算的两个参数,都是由程序默认提供,那么如果说现在两个计算的参数通过初始化参数传递呢?

 1 public class Test {
 2     public static void main(String args[]) {
 3         System.out.println("1、除法计算开始。");
 4         try {
 5             int x = Integer.parseInt(args[0]); // 接收参数
 6             int y = Integer.parseInt(args[1]); // 接收参数
 7             int result = x / y;
 8             System.out.println("2、除法计算结果:" + result);
 9         } catch (ArithmeticException e) {
10             e.printStackTrace();
11         } finally {
12             System.out.println("不管是否出现异常都执行");
13         }
14         System.out.println("3、除法计算结束。");
15     }
16 }

  这个时候,数据由外部传送,那么就有可能出现以下几类问题: 
  (1)执行时不输入参数(java TestDemo),ArrayIndexOutOfBoundsException,未处理; 
  (2)输入的参数不是数字(java TestDemo a b),NumberFormatException,未处理; 
  (3)被除数为0(java TestDemo 10 0),ArithmeticException,已处理。 
  可以发现,以上的程序实际上是存在三种异常,而程序之中只能够处理一种,而对于不能处理的异常,发现程序依然会直接中断执行。 
  加入多个catch:

 1 public class Test {
 2     public static void main(String args[]) {
 3         System.out.println("1、除法计算开始。");
 4         try {
 5             int x = Integer.parseInt(args[0]);
 6             int y = Integer.parseInt(args[1]);
 7             int result = x / y;
 8             System.out.println("2、除法计算结果:" + result);
 9         } catch (ArithmeticException e) {
10             e.printStackTrace();
11         } catch (ArrayIndexOutOfBoundsException e) {
12             e.printStackTrace();
13         } catch (NumberFormatException e) {
14             e.printStackTrace();
15         } finally {
16             System.out.println("不管是否出现异常都执行");
17         }
18         System.out.println("3、除法计算结束。");
19     }
20 }

  现在,程序比之前更健壮了。

 三,异常处理流程

  以上已经完成了异常的基本处理,但是所有的异常都想之前那样一条条判断似乎是不可能完成的一件事,因为日后肯定会接触到一些不常见的异常信息,那么下面就首先研究一下JVM异常的处理流程和结构。

  先查看两个异常类的继承结构:

  (1)ArithmeticException:

1 java.lang.Object
2     |- java.lang.Throwable
3          |- java.lang.Exception
4               |- java.lang.RuntimeException
5                  |- java.lang.ArithmeticException

  (2)ArrayIndexOutOfBoundsException:

1 java.lang.Object
2    |- java.lang.Throwable
3       |- java.lang.Exception
4          |- java.lang.RuntimeException
5              |- java.lang.IndexOutOfBoundsException
6                 |-java.lang.ArrayIndexOutOfBoundsException

  可以发现,所有的异常类型最高的继承类是Throwable,Throwable下有两个子类: 
  (1)Error:指的是JVM错误,这个时候的程序并没有执行,无法处理; 
  (2)Exception:指的是程序之中出现的错误信息,可以进行异常处理。

通过继承关系可以发现,在进行日后异常处理的时候是以Exception为主,并且可以形成以下的异常处理流程:

  

  (1)如果程序中产生了异常,那么JVM根据异常的类型,实例化一个指定异常类的对象;

  (2)如果这时程序中没有任何的异常处理操作,则这个异常类的实例化对象将交给JVM进行处理,而JVM的默认处理方式就是进行异常信息的输出,而后中断程序执行;

  (3)如果程序中存在了异常处理,则会由try语句捕获产生的异常类对象;

  (4)与try之后的每一个catch进行匹配,如果匹配成功,则使用指定的catch进行处理,如果没有匹配成功,则向后面的catch继续匹配,如果没有任何的catch匹配成功,则这个时候将交给JVM执行默认处理;

  (5)不管是否有异常都会执行finally程序,如果此时没有异常,执行完finally,则会继续执行程序之中的其他代码,如果此时有异常没有能够处理(没有一个catch可以满足),那么也会执行finally,但是执行完finally之后,将默认交给JVM进行异常的信息输出,并且程序中断。

  通过以上的分析可以发现,实际上catch捕获异常类型的操作,就和方法接收参数是一样的,那么按照之前所学习过的对象多态性来讲,所有的异常类都是Exception的子类,那么这个时候,实际上所有的异常都可以使用Exception进行接收:

 1 public class Test {
 2     public static void main(String args[]) {
 3         System.out.println("1、除法计算开始。");
 4         try {
 5             int x = Integer.parseInt(args[0]);
 6             int y = Integer.parseInt(args[1]);
 7             int result = x / y;
 8             System.out.println("2、除法计算结果:" + result);
 9         } catch (Exception e) {
10             e.printStackTrace();
11         } finally {
12             System.out.println("不管是否出现异常都执行");
13         }
14         System.out.println("3、除法计算结束。");
15     }
16 }

这时应该可以感受到异常处理所带来的好处了。但是这种操作也存在一种问题:如果在一些异常处理要求严格的项目之中,异常必须分别处理,如果现在异常的处理要求不是很严格,直接编写Exception就足够了。

未完待续。。。

原文地址:https://www.cnblogs.com/revel171226/p/8288832.html

时间: 2024-08-05 18:36:44

Java 异常的捕获与处理详解 (一)的相关文章

Java 异常的捕获与处理详解(二)

(一).throws关键字 throws关键字主要是在定义上使用的,表示的是此方法中不进行异常处理,而交给被调用处处理. 例如: 1 class MyMath { 2 public int div(int x, int y) throws Exception { 3 return x / y; 4 } 5 } 现在div()方法之中抛出一个异常出来,表示所有异常交给被调用处进行处理. 1 class MyMath { 2 public int div(int x, int y) throws E

“全栈2019”Java异常第二十章:自定义异常详解

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异常第二十章:自定义异常详解 下一章 "全栈2019"Java异常第二十一章:finally不被执行的情况 学习小组 加入同步学习小组,共同交流与进步. 方式一:关注头条号Gorhaf,私信"Java学习小组". 方式二:关注公众号Gorhaf,回复"Java学

Java并发编程之---Lock框架详解

Java 并发开发:Lock 框架详解 摘要: 我们已经知道,synchronized 是Java的关键字,是Java的内置特性,在JVM层面实现了对临界资源的同步互斥访问,但 synchronized 粒度有些大,在处理实际问题时存在诸多局限性,比如响应中断等.Lock 提供了比 synchronized更广泛的锁操作,它能以更优雅的方式处理线程同步问题.本文以synchronized与Lock的对比为切入点,对Java中的Lock框架的枝干部分进行了详细介绍,最后给出了锁的一些相关概念. 一

java的集合框架最全详解

java的集合框架最全详解(图) 前言:数据结构对程序设计有着深远的影响,在面向过程的C语言中,数据库结构用struct来描述,而在面向对象的编程中,数据结构是用类来描述的,并且包含有对该数据结构操作的方法. 在Java语言中,Java语言的设计者对常用的数据结构和算法做了一些规范(接口)和实现(具体实现接口的类).所有抽象出来的数据结构和操作(算法)统称为Java集合框架(JavaCollectionFramework). Java程序员在具体应用时,不必考虑数据结构和算法实现细节,只需要用这

Java的集合框架最全详解(图)

纯个人整理,如有错误请指正. java的集合框架最全详解(图) 前言:数据结构对程序设计有着深远的影响,在面向过程的C语言中,数据库结构用struct来描述,而在面向对象的编程中,数据结构是用类来描述的,并且包含有对该数据结构操作的方法. 在Java语言中,Java语言的设计者对常用的数据结构和算法做了一些规范(接口)和实现(具体实现接口的类).所有抽象出来的数据结构和操作(算法)统称为Java集合框架(JavaCollectionFramework). Java程序员在具体应用时,不必考虑数据

Java魔法堂:String.format详解

Java魔法堂:String.format详解   目录     一.前言    二.重载方法     三.占位符     四.对字符.字符串进行格式化     五.对整数进行格式化     六.对浮点数进行格式化     七.对日期时间进行格式化     八.其他转换符  九.总结   参考 一.前言 String.format 作为文本处理工具,为我们提供强大而丰富的字符串格式化功能,为了不止步于简单调用 String.format("Hello %s", "John&q

Java魔法堂:String.format详解 (转载)

Java魔法堂:String.format详解   目录 一.前言 二.重载方法 三.占位符 四.对字符.字符串进行格式化 五.对整数进行格式化 六.对浮点数进行格式化 七.对日期时间进行格式化 八.其他转换符   九.总结   参考 一.前言 String.format 作为文本处理工具,为我们提供强大而丰富的字符串格式化功能,为了不止步于简单调用 String.format("Hello %s", "John"); ,下面将笔记整理并记录下来. 二.重载方法 /

JAVA通过JDBC连接Oracle数据库详解【转载】

JAVA通过JDBC连接Oracle数据库详解 (2011-03-15 00:10:03) 转载▼http://blog.sina.com.cn/s/blog_61da86dd0100q27w.html Java连接Oracle步骤: 1.注册加载驱动 驱动名:DRIVER="oracle.jdbc.driver.OracleDriver"; Class.forName("驱动类名"); 2.获得连接 数据库地址: URL="jdbc:oracle:thi

【转】Java魔法堂:String.format详解

Java魔法堂:String.format详解   目录     一.前言    二.重载方法     三.占位符     四.对字符.字符串进行格式化     五.对整数进行格式化     六.对浮点数进行格式化     七.对日期时间进行格式化     八.其他转换符  九.总结   参考 一.前言 String.format 作为文本处理工具,为我们提供强大而丰富的字符串格式化功能,为了不止步于简单调用 String.format("Hello %s", "John&q