第 14 讲 异常处理

32
1/ 第 14 第 第第第第

Upload: ludwig

Post on 24-Jan-2016

92 views

Category:

Documents


4 download

DESCRIPTION

第 14 讲 异常处理. 教学目标. 理解 Java 异常处理机制原理 掌握捕获与处理异常方法 掌握 Java 自定义异常及处理特殊异常的方法. 引例. public class Ex8_1{ public static void main (String args[]) { int i = 0; String greetings [] = { “ Hello world! ” , “ No , I mean it! ” , “ HELLO WORLD!! ” }; while ( i < 4 ) { - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 第 14 讲 异常处理

1/

第 14 讲 异常处理

Page 2: 第 14 讲 异常处理

教学目标•理解 Java异常处理机制原理

•掌握捕获与处理异常方法

•掌握 Java自定义异常及处理特殊异常的方法

Page 3: 第 14 讲 异常处理

引例public class Ex8_1{  public static void main (String args[]) {    int i = 0;    String greetings [] = { “Hello world!” , “ No , I mean it!” , “ HELLO WORLD!!”};   while (i < 4) {    System.out.println (greetings[i]);    i++;   }  }}

运行结果: Hello world!No , I mean it!HELLO WORLD!!Exception in thread "main"

java.lang.ArrayIndexOutOfBoundsException: 3 at Ex8_1.main(Ex8_1.java:9)

Page 4: 第 14 讲 异常处理

引例分析 从上述例题可以发现,在 Java语言中,并不是所有程

序都是完美的和不会发生运行时错误的,我们将程序运行时发生的错误叫做异常。下面任何一种情况都会出现异常:•想打开的文件不存在;•在访问数组时,数组的下标值超过了数组允许的范围;•整除时除数为 0 ;•正在装载的类文件丢失。

Page 5: 第 14 讲 异常处理

异常机制的作用• Java中的每个异常类都代表了一种运行错误,每当 Java

程序运行过程中发生一个可识别的运行错误时,系统都会产生一个相应的该异常类的对象,即产生一个异常。一旦一个异常对象产生了,系统中就一定有相应的机制来处理它,确保不会产生死机、死循环或其他对操作系统的损害,从而保证了整个程序运行的安全性,这就是 Java的异常处理机制。•在没有异常处理的语言中,必须使用 if-else或 switch等

语句,捕捉程序中所有可能发生的错误情况。 Java的异常处理机制恰好弥补这个不足,它具有易于使用、可自定义异常类、允许抛出异常且不会降低运行速度等优点。因而在设计 Java程序时,充分利用 Java异常处理机制,可大大提高程序的稳定性及效率。

Page 6: 第 14 讲 异常处理

异常和异常类•作为面向对象语言,异常与其他语言要素一样,是面向对

象范围的一部分,是异常类的对象。 Java所有的异常对象都是继承 Throwable类的实例, Throwable类是类库java.lang包中的一个类,它派生了两个子类: Error类和 Exception类。如图 8-1所示。• Error类被认为是不能恢复的严重错误,如系统内部错误、

资源耗尽错误等。由于在些种情况下,除了通知用户并试图终止程序外几乎是不能做其他任何处理的,因此,不应该抛出这种类型的错误,而是直接让程序中断。• Exception类定义可能遇到的轻微错误,分为继承RuntimeException类的异常和非继承RuntimeException类的异常。这时,可以写代码来处理异常并继续程序执行,而不是让程序中断。

Page 7: 第 14 讲 异常处理

异常和异常类

图 8-1 Java异常继承关系示意图

Page 8: 第 14 讲 异常处理

异常处理•引例中,异常发生后, Java在运行时将这个异常抛

出,可是抛出后没有程序代码去捕捉它,所以程序被中断。•如果添加捕捉异常的程序代码,则可针对不同的异常

做妥善的处理。 try{} catch(){} finally{}

Page 9: 第 14 讲 异常处理

异常处理示例public static void main (String args[]) { int i = 0; String greetings [] = {“Hello world!”, “No, I mean it!”, "HELLO WORLD!!“ }; while (i < 4) {       try {System.out.println (greetings[i]);   // 可能出现数组越界异常的代码 }      catch (ArrayIndexOutOfBoundsException e){ // 数组越界的异常处理           System.out.println( "Re-setting Index Value");            i = -1;       }       finally {     System.out.println(“This is always printed”); // 始终在循环过程       i++;      }}

运行结果: Hello world!This is always printedNo , I mean it!This is always printedHELLO WORLD!! This is always printedRe-setting Index Value This is always printed

Page 10: 第 14 讲 异常处理

异常处理方法

•通过上例发现,当一个方法被调用时如果发生异常,必须采取相应措施解决出现的问题,即进行异常处理。有两种方法解决以上问题。•第一,通过 try-catch语句捕获异常,并调用方法处理它。•第二,被调用的方法自己不处理异常,该异常将被抛回到调用

它的方法中。它是使用 throws来实现的,例如, public void troublesome() throws IOException

关键字 throws之后是 troublesome()出现的所有异常列表,该方法可以抛回 IOException到调用它的程序中。如果有多个异常被抛出,可以使用逗号分开的列表列出所有的异常类。

声明异常

Page 11: 第 14 讲 异常处理

声明异常示例import java.io.*;class Ex8_3 extends Exception{

  void test(double x) throws Ex8_3{ //声明异常   if(x < 0.0) throw new Ex8_3 ();   else System.out.println(Math.sqrt(x));  }  public static void main(String args[]) throws IOException{   Ex8_3 me = new Ex8_3 ();   try{    System.out.println("求平方根 : ");    BufferedReader input = new BufferedReader(new InputStreamReader(System.in));    String str = input.readLine();    me.test(Double.parseDouble(str));   }catch(Ex8_3 e){    System.out.println("输入的数是负数,不能求平方根 ");   }  }}

运行结果: C:\java>java Ex8_3求平方根 :42.0     C:\java>java Ex8_3求平方根 :-4输入的数是负数,不能求平方根

程序分析:在这个程序中,定义的异常类继承了 Exception异常类。在 test()方法首部声明了异常 Ex8_3异常,并在其方法中用throw子句指定了可能抛出的异常。

Page 12: 第 14 讲 异常处理

捕获异常•通过例 8.2可知异常的捕获和处理是由 try、 catch和 finally

所组成的程序块完成的,我们先探讨 try-catch语句块,其格式如下:try{         可能产生异常的代码 //try块 }catch (ExceptionType e1 ){ //要捕获的异常类型

对此异常的处理 //异常处理,可以为空}…… catch(ExceptionType en ){ }

•异常的捕获和处理流程如下:1. 如果 try块中没有代码产生异常,那么程序将跳过 catch

子句2. try块中的任意代码产生一个属于 catch子句所声明类的异

常,程序将跳过 try块中的剩余代码,并执行与所产生异常类型匹配的 catch子句的异常处理代码。3. 如果 try块中的代码产生一个不属于所有 catch子句所声明类的异常,那么该方法会立即退出。

Page 13: 第 14 讲 异常处理

•这种方式将所有的代码都置入一个 try块内集中处理,因此大量不同的方法调用可能生成相同的异常,只需要一个控制器就可以捕获处理。当然,如果自己捕获并处理异常,就不用在方法头部用 throws语句来声明异常了。•我们已经知道,当异常产生时,方法的执行流程非线

性方式执行,甚至在没有匹配 catch子句时,可能从方法中过早退出。但有时,无论异常发生还是被捕获,都希望有些语句必须执行。例如,首先要打开文件,接着对文件进行处理,然后关闭文件,当然不希望将关闭文件的这段代码由异常处理来进行。 finally语句就提供了这种问题的解决办法

捕获异常(续)

Page 14: 第 14 讲 异常处理

重新抛出异常Graphics g = image.getGraphics();try{    可能产生异常的代码 //try块}catch(MalformedURLException e) {      System.out.println( "an MalformedURLException!!" );

g.dispose();   //释放对象 g      throw e ; //重新抛出异常 e}

• 当出现异常时, try块里的剩余代码都不会被执行,那么对象 g将一直被保持,直到它的 finalize方法释放它(占用内存),因此当不知道如何处理此异常时,在产生此异常之前需要对本地资源进行清理,如在 catch子句里释放对象 g ,然后抛出已经捕获的异常。这就是重新抛出异常的最常见的原因。

Page 15: 第 14 讲 异常处理

finally子句•但是这种方法比较烦琐,因为在 try块的正常代码里也必须

要清除本地对象,清除对象的代码将出现在两个地方,一个在 try块里,一个在 catch子句里。当有多个 catch子句时,每个子句都要清除对象。为解决这种重复性, Java提供了finally子句。Graphics g = image.getGraphics();try{   可能产生异常的代码 //try块} catch(MalformedURLException e) {   System.out.println("an MalformedURLException!!!“);

}finally{    g.dispose(); //释放对象 g} 

Page 16: 第 14 讲 异常处理

• finally子句是必须执行的,无论程序是否捕获到异常。当程序中出现 finally子句时,执行流程分四种情况:1. 方法不抛出任何异常。程序将执行 try块里的所有代码,然后

执行 finally子句的代码,再执行后续代码。2. 方法抛出 catch子句能够捕获的异常,而且 catch子句没有

重新抛出异常。此时,程序将执行 try块中的代码,直到抛出异常,然后 try块的剩余代码被跳过,执行匹配的 catch子句代码,接着执行 finally子句的代码,再执行后续代码

3. 方法抛出 catch子句能够捕获的异常,而且 catch子句重新抛出异常。执行过程与第2 种情况相同,只是最后异常被重新抛出。

4. 方法抛出不能被 catch子句捕获的异常。此时,程序先执行try块里的代码,直到抛出异常,然后跳过 try块的剩余代码,执行 finally子句的代码,再将异常抛出给该方法的调用者。

finally子句(续)

Page 17: 第 14 讲 异常处理

抛出异常•Java程序在运行时如果引发了一个可以识别的错误,就会产生

一个与该错误相对应的异常类的对象,这个过程称作异常的抛出,实际是相应异常类的实例的抛出。根据异常类的不同,抛出异常的方式也有所不同

系统自动抛出的异常——所有的系统定义的运行错误异常语句抛出的异常

用户自定义的异常不可能依靠系统自动抛出,必须用 throw语句明确地抛出一个异常。首先,必须知道什么情况下产生了某种异常对应的错误,然后为这个异常类创建一个实例,最后用 throw语句抛出。下面是 throw语句的常用格式:返回类型 方法名(参数列表) throws 要抛出的异常类名列

表 {      ……      throw 异常实例; ……}

Page 18: 第 14 讲 异常处理

抛出异常(续)•这样定义方法后,可通知所有要调用这个方法的上层方法,准备接受和处理它在运行中可能会抛出的异常。•一般情况下,这种抛出语句应在某种条件满足下执行,例

如, void MyMethod() throws MyException{ // 可能在程序中抛出

MyException 异常 …… if ( i>100)

throw ( new MyException()); ……}

•如果方法中的 throw语句不止一个,则应该在方法头throws后列出所有可能的异常。

Page 19: 第 14 讲 异常处理

抛出异常(续)•若某个方法MyMethod可能产生Exception1、 Exception2和 Exception3 三种异常,而它们又都是 Super_Exception类的子类,则应在相应的方法中声明可能抛出的异常类,语句如下:void MyMethod() throws Exception1,Exception2,Exception3

{       ……                       //可能抛出这三个异常} 

•还可以只简单地声明抛出 Super_Exception,下面这种方式和上面的是等价的。void MyMethod() throws Super_Exception{           ……//可能抛出这三个异常的父类}

Page 20: 第 14 讲 异常处理

抛出异常(续)

•在 Java语言中如果调用了一个可能产生异常的方法,如果调用方法不处理这个异常,则在调用方法中要对这个异常类进行声明,如下面代码: void YourMethod() throws Super_Exception{           ……           MyMethod(); //调用了可能会抛出异常的方法 ……}

• Java语言要求所有用 throws关键字声明的类和用 throw抛出的对象必须是 Throwable类或其子类。但如果试图抛出一个不可抛出的异常, Java编译器将会报错。

Page 21: 第 14 讲 异常处理

抛出异常-重新抛出异常•重新抛出异常 前面说过,被调用方法自己可以不处理异常,只是在方

法头部简单声明(声明异常),由调用方法决定如何处理异常,或者也可以在被调用方法中捕获异常并进行处理。那么该不该捕获异常,有何规则?一般来说,捕获知道如何处理的异常,对于不知道如何处理的异常则进行声明,告诉调用方法,一个异常可能会被抛出。需要进行下一步处理的异常采用重新抛出异常的方法。

Page 22: 第 14 讲 异常处理

重新抛出异常示例// 一个重新抛出异常的示例public class Ex8_4 {  public static void found() throws Exception{       System.out.println("the original exception in found()");       throw new Exception("thrown from found()");  }  public static void main(String args[]) throws Exception{       try{   found();   }   catch(Exception e){

System.out.println(“catch in main()");throw e; }

  }}

运行结果:the original exception in found()catch in main()Exception in thread "mian" thrown from found()       at Ex8_3.found(Ex8_3.java:4)       at Ex8_3.main(Ex8_3.java:7)

Page 23: 第 14 讲 异常处理

自定义异常•为了适应各种异常, Java语言可以通过继承的方式编写

自己的异常类。因为所有的异常类均继承自 Exception类,所以自定义类也必须继承这个类。自定义异常类的语法如下,class 异常类名 extends Exception{ 

类体}

•在自定义异常类里通过编写新的方法来处理相关的异常,甚至可以不编写任何语句也可正常工作,因为 Exception类已提供相当丰富的方法。

Page 24: 第 14 讲 异常处理

自定义异常示例// 创建自己的异常类。public class Ex8_5 extends Exception {  private String reason;  private int port;  public Ex8_5 (String reason , int port){    this.reason = reason;   this.port = port;  }  public String getReason() {   return reason;  }  public int getPort() {   return port;  }}

•程序分析:异常类和普通类一样,可以有成员变量、方法,能对变量进行操作。同系统异常一样,可使用throw语句来抛出自定义异常。

Page 25: 第 14 讲 异常处理

自定义异常类及其使用示例class MyException extends Exception{ public MyException(){ } public MyException(String message){ super(message); } }public class Ex8_6{ public static void f() throws MyException{   System.out.println("Throwing MyException");   throw new MyException("the second constructor! "); } public static void main(String args[]){ try{ f(); } catch(MyException e) {  e.printStackTrace(); } } }

运行结果:Throwing MyExceptionMyException:the second construtor!at Ex8_6.f(Ex8_6.java:7)at Ex8_5.main(Ex8_5.java:12)

程序分析:该例题通过继承异常类 Exception创建了自己的异常类 MyException,并增加了两个构造方法,第一个没有明确指明调用父类构造方法,但是编译器会自动调用父类默认构造方法,第二个通过使用 super关键字,调用了参数为 String类型的父类构造方法。 PrintStackTrace()方法将打印出“ the second constructor!”信息和异常发生地点的方法调用的顺序。

Page 26: 第 14 讲 异常处理

多 catch 语句使用示例public class Ex8_6 {   public static void test(int i) { try {    int x = i;     if (x>0)       throw new ArithmeticException ("this is a Arithmetic

Exception!");    else if (x<0)      throw new NullPointerException ("this is a NullPointer

Exception!");     else      throw new Exception("this is a Exception!"); } catch(ArithmeticException e){ System.out.println(e.toString());}

Page 27: 第 14 讲 异常处理

catch(NullPointerException e) { System.out.println(e.toString()); } catch(Exception e) { System.out.println(e.toString()); } } public static void main(String[] args) {    test(-1); test(0); test(1);  } }

多 catch 语句使用示例(续)运行结果:java.lang.NullPointerException: this is a NullPointer Exception!java.lang.Exception: this is a Exception!java.lang.ArithmeticException: this is a Arithmetic Exception!

程序分析:在一个 try区中存在的异常可能有多种类型,这时需要用多个 catch块来捕获和处理这些异常。程序的main()方法中,给出了三个测试值,分别会有三个异常产生,每个异常发生时,, Java将依次逐个检查这些 catch语句,发现与抛出的异常类型匹配时就执行那一段处理代码,而其余的不会被执行。

Page 28: 第 14 讲 异常处理

多 catch语句使用注意事项•为了防止可能遗漏某一类异常 catch语句,可以在后

面放置一个捕获 Exception类的 catch语句。 Exception是可以从任何类方法中“抛”出的基本类型。,因为它能够截获任何异常,从而使后面具体的异常 catch语句不起作用,所以需放在最后一个位置。如果将捕获 Exception的 catch放在前面,编译就通不过。

Page 29: 第 14 讲 异常处理

本章小结•异常处理是成功设计一个 Java程序的保证。本章介绍了Java语言中异常和异常类的概念,讨论了异常处理的方法。•异常是程序运行时出现的非正常情况,可以是由于程序设

计本身的错误,也有可能是由于运行中出现了不可解决的问题造成了异常。异常往往会导致程序运行失败或者程序运行的终止。•在 Java语言中提供了一系列的异常处理方法,程序中出

现的异常都是以某个异常类的实例(对象)形式存在。

Page 30: 第 14 讲 异常处理

本章小结•异常类都是 Exception类的子类,分为两种,一种是在Java类库中已经定义好的,叫系统定义的运行异常;另一种是由用户自己根据所设计软件的具体情况定义的异常,它也是 Exception类或其子类,这一类异常在错误产生时无法自动地抛出,而是要用户设计代码创建对应的对象,并手动地用 throw语句抛出。当然,凡是用户定义的异常,还要在可能产生这些异常的地方用 throws语句声明这些异常类。•在 Java的异常处理机制中,重点是异常的捕获和处

理。 Java语言用 try-catch-finally语句块来捕获和处理异常,当抛出多个异常时,需要多个 catch块来捕获和处理。此时,应注意 catch块的捕获规则,防止捕获异常的失败。

Page 31: 第 14 讲 异常处理

本章小结•在 Java中可以通过继承 Exception类创建自定义异常类,

一旦创建了自定义异常类,则该异常类的使用方法等同于系统异常类。•异常处理可以提高程序的健壮性,学会如何处理异常,如

何在程序中应用异常处理机制来提高所设计程序的健壮性,设计出更完善的程序将是学习 Java编程中的一个非常关键的问题。

Page 32: 第 14 讲 异常处理

作业

•推荐书籍:《 Robust Java中文版 :Java异常处理、测试与调

试》