210 likes | 309 Vues
第 6 章 Java 的异常处理. 学习目标 : 异常的基本概念 Throwable 类及其子类 运行时异常 捕获异常 声明异常 抛出异常 自定义异常 异常处理机制的优点 使用异常处理机制的一些原则. 6.1 异常的基本概念. 异常是在程序运行过程中发生的异常事件,比如除 0 溢出、数组越界、文件找不到等,这些事件的发生将阻止程序的正常运行。程序设计时,必须考虑到可能发生的异常事件并做出相应的处理。 C 语言中,通过使用 if 语句来判断是否出现了异常并进行处理。但是,这种错误处理机制会导致不少问题。 例 : main(){
E N D
第6章 Java的异常处理 • 学习目标: • 异常的基本概念 • Throwable类及其子类 • 运行时异常 • 捕获异常 • 声明异常 • 抛出异常 • 自定义异常 • 异常处理机制的优点 • 使用异常处理机制的一些原则
6.1异常的基本概念 异常是在程序运行过程中发生的异常事件,比如除0溢出、数组越界、文件找不到等,这些事件的发生将阻止程序的正常运行。程序设计时,必须考虑到可能发生的异常事件并做出相应的处理。 C语言中,通过使用if语句来判断是否出现了异常并进行处理。但是,这种错误处理机制会导致不少问题。 例: main(){ int a,b,c; scanf(“%d%d”,&a,&b); if(b!=0) c=a/b; else printf(“除数不能为0”); }
6.1异常的基本概念 Java通过面向对象的方法来处理异常。 异常处理机制 在一个方法的运行过程中,如果发生了异常,则这个方法生成代表该异常的一个对象,并把它交给运行时系统,运行时系统寻找相应的代码来处理这一异常。我们把生成异常对象并把它提交给运行时系统的过程称为抛出(throw)一个异常。运行时系统在方法的调用栈中查找,从生成异常的方法开始进行回朔,直到找到包含相应异常处理的方法为止,这一个过程称为捕获(catch)一个异常。 生活中事件的处理机制 在社会活动中,如果发生了火灾、交通事故、遭窃、生病等突然发生的异常事件,我们会打电话报警(throw)。城市中的各个部门中一定会有一个来处理这个突发事件(catch)。
6.2 Throwable类及其子类 用面向对象的方法处理异常,就必须建立类的层次。类 Throwable位于这一类层次的最顶层,只有它的后代才可以作为一个异常被抛出。
6.2 Throwable类及其子类 Error类对象(如动态链接错误等),由Java虚拟机生成并抛出。通常,Java程序不对这类异常进行处理。 Exception类对象是Java程序处理或抛出的对象。它有各种不同的子类分别对应于不同类型的异常。 (1)RunTimeException类及其继承类: java程序在运行时生成异常,如被0除( ArithmeticException)、数组下标越界( ArrayIndexOutOfBoundsException)等,其产生比较频繁,处理麻烦,对程序可读性和运行效率影响太大。因此由系统检测, 用户可不做处理,系统将它们交给缺省的异常处理程序(当然,必要时,用户可对其处理)。 (2)除此(RunTimeException)之外,其他的异常类:必须被捕获或被重新抛出,否则编译会错误。
6.2 Throwable类及其子类 Throwable类 Error类 Exception类 IOException RunTimeException AWTException …… InterruptedException ArithmeticException ClassNotFoundException ArrayIndexOutOfBoundsException
6.3 运行时异常 运行时异常是由Java运行时系统在程序的运行过程中检测到的,它可能在程序的任意部位发生,而且其数目可能很大,因此Java编译器允许程序不对它进行处理。这时,Java运行时系统会把生成的运行时异常对象交给缺省的异常处理程序,在标准输出上显示异常的内容以及发生异常的位置。 例: public class RuntimeExceptionExample{ public static void main( String args[] ){ int i=0; int r=4/i; } } 运行结果为:C:\>java RuntimeExceptionProc java.lang.ArithmeticException: /by zero at RuntimeExceptionProc.main(RuntimeExceptionProc.java:4)
6.4 捕获异常 我们可以用try-catch-finally语句来捕获一个或多个异常,语法结构如下: try { 可能产生异常的代码段; } catch(异常类名1 对象名1) { 处理语句组1; } catch(异常类名2 对象名2) { 处理语句组2; } …… finally { 最终处理语句; }
6.4 捕获异常 1. try语句 try语句用大括号{}指定了一段代码,该段代码可能会抛出一个或多个异常,同时,该段代码也指定了它后面的catch语句所捕获的异常的范围。 例: try { int[] a={1,2,3,4,5}; int sum=0; for(int i=0;i<=5;i++) sum=sum+a[i]; System.out.println(sum); }
6.4 捕获异常 2. catch语句 catch语句的参数类似于方法的声明,包括一个异常类型和一个异常对象。异常类型必须为Throwable类的子类,它指明了catch语句所处理的异常类型,异常对象则由运行时系统在try所指定的代码块中生成并被捕获,大括号中包含对象的处理,其中可以调用对象的方法。 catch语句可以有多个,分别处理不同类的异常。Java运行时系统从上到下分别对每个catch语句处理的异常类型进行检测,直到找到与类型相匹配的catch语句为止。这里,类型匹配指catch所处理的异常类型与生成的异常对象的类型完全一致或者是它的父类,因此,catch语句的排列顺序应该是从特殊到一般(ExceptionExample1.java)。 也可以用一个catch语句处理多个异常类型,这时它的异常类型参数应该是这多个异常类型的父类,程序设计中要根据具体的情况来选择catch语句的异常处理类型(ExceptionExample2.java)。
6.4 捕获异常 金属垃圾 塑料垃圾 玻璃垃圾 废纸垃圾 垃圾桶
6.4 捕获异常 3. finally语句 try所限定的代码中,当抛出一个异常时,其后的代码不会被执行。通过finally语句可以指定一块代码。无论try所指定的程序块中抛出或不抛出异常,也无论catch语句的异常类型是否与所抛出的异常的类型一致,finally所指定的代码都要被执行,它提供了统一的出口。 通常在finally语句中可以进行资源的清除工作。如关闭打开的文件等。 例子: ExceptionExample3 .java
6.5 声明异常 在方法中使用try-catch-finally可以由这个方法来处理它所生成的异常。在有些情况下,一个方法并不需要处理它所生成的异常,而是向上传递,由调用它的方法来处理这些异常,这时就要用到throws子句,它包含在方法的声明中,其格式如下: returnType methodName([paramlist]) throws exceptionList 其中在ExceptionList中可以声明多个异常,用逗号隔开。 例: static void fun( int sel ) throws ArithmeticException,ArrayIndexOutOfBoundsException 完整例子: ExceptionExample4.java 在fun()方法中生成的异常通过调用栈传递给main()方法,由main()方法进行处理。 注意:对非运行时异常,必须捕获或声明。
6.6 抛出异常 在捕获一个异常前,必须有一段Java代码生成一个异常对象并把它抛出。抛出异常的代码可以是你的Java程序,或者是JDK中某个类,或者是Java运行时系统。它们都是通过throw语句来实现的。 throw语句的格式为:throw ThrowableObject; 其中ThrowableObject必须为Throwable类或其子类的对象。 例如我们可以用 throw new ArithmeticExcption();来抛出一个算术异常(ExceptionExample5.java)。 另外,我们还可以定义自己的异常类,并用throw语句来抛出它。
6.7 自定义异常 创建用户自定义异常的语法格式如下: class 自定义异常 extends 父类异常名 { … } 例: class MyException extends Exception { MyException(String msg) { super(msg); } MyException() { } } 完整例子:ExceptionExample6.java
6.8 异常处理机制的优点 • Java通过面向对象的方法进行异常处理,把各种不同的异常事件进行分类,体现了良好的层次性,提供了良好的接口,这种机制对于具有动态运行特性的复杂程序提供了强有力的控制方式。 • 2. Java的异常处理机制使得处理异常的代码和“常规”代码分开,减少了代码的数量,增强了程序的可读性。(大家可以比较一下用if语句来处理异常的情形,这时需要进行一系列条件的判定)。 • 3. Java的异常处理机制使得异常事件可以沿调用栈自动向上传播,而不是C语言中通过函数的返回值来传播,这样可以传递更多的信息并且简化代码的编写。 • 4. 由于把异常事件当成对象来处理,利用类的层次性我们可以把多个具有相同父类的异常统一处理,也可以区分不同的异常分别处理,使用非常灵活。
6.8 使用异常处理机制的一些原则 • 1.对非运行时异常必须捕获或声明,而对运行时异常则不必,可以交给Java运行时系统来处理。 • 2.对于自定义的异常类,通常把它作为类Exception子类,而不作为类Error的子类,因为Error类通常用于系统内严重的硬件错误。并且在多数情况下,不要把自定义的异常类作为运行时异常类RuntimeException子类。另外,自定义异常类的类名常常以Exception结尾。 • 3.在捕获或声明异常时,要选取合适类型的异常类,注意异常的类层次,根据不同的情况使用一般或特殊的异常类。 • 根据具体的情况选择在何处处理异常。是在方法内捕获并处理呢?还是用throws子句把它交给调用栈中上层的方法去处理? • 5. 使用finally语句为异常处理提供统一的出口。
6.9 实际应用 程序功能 将键盘输入保存到文件中,要求只接收英文字母,如果输入其他 字符,将文件自动删除。 目的: 用于理解将业务代码和异常处理分开的概念。
// ExceptionExample7。java import java.io.*; public class ExceptionExample7 { public static void main(String args[]) throws IOException { Inputdata a=new Inputdata(); try { a.input(); } catch(MyException e) { boolean flag; e.fout.close(); File f=new File("data.txt"); flag=f.delete(); if(flag==true) System.out.println("成功删除文件"); else System.out.println("删除文件失败"); } } }
// MyException.java import java.io.*; public class MyException extends Exception { public MyException(FileOutputStream fout) { this.fout=fout; } public FileOutputStream fout; }
//Inputdata.java import java.io.*; public class Inputdata { public void input() throws IOException,MyException { int i; FileOutputStream fout; fout=new FileOutputStream("data.txt"); i=System.in.read(); while(i!=13) { if(i<97||i>122) { throw new MyException(fout); } fout.write((char)i); i=System.in.read(); } fout.close(); } }