1 / 32

第 14 讲 异常处理

第 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 ) {

ludwig
Download Presentation

第 14 讲 异常处理

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第14讲 异常处理

  2. 教学目标 • 理解Java异常处理机制原理 • 掌握捕获与处理异常方法 • 掌握Java自定义异常及处理特殊异常的方法

  3. 引例 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)

  4. 引例分析 从上述例题可以发现,在Java语言中,并不是所有程序都是完美的和不会发生运行时错误的,我们将程序运行时发生的错误叫做异常。下面任何一种情况都会出现异常: • 想打开的文件不存在; • 在访问数组时,数组的下标值超过了数组允许的范围; • 整除时除数为0; • 正在装载的类文件丢失。

  5. 异常机制的作用 • Java中的每个异常类都代表了一种运行错误,每当Java程序运行过程中发生一个可识别的运行错误时,系统都会产生一个相应的该异常类的对象,即产生一个异常。一旦一个异常对象产生了,系统中就一定有相应的机制来处理它,确保不会产生死机、死循环或其他对操作系统的损害,从而保证了整个程序运行的安全性,这就是Java的异常处理机制。 • 在没有异常处理的语言中,必须使用if-else或switch等语句,捕捉程序中所有可能发生的错误情况。Java的异常处理机制恰好弥补这个不足,它具有易于使用、可自定义异常类、允许抛出异常且不会降低运行速度等优点。因而在设计Java程序时,充分利用Java异常处理机制,可大大提高程序的稳定性及效率。

  6. 异常和异常类 • 作为面向对象语言,异常与其他语言要素一样,是面向对象范围的一部分,是异常类的对象。Java所有的异常对象都是继承Throwable类的实例,Throwable类是类库java.lang包中的一个类,它派生了两个子类:Error类和Exception类。如图8-1所示。 • Error类被认为是不能恢复的严重错误,如系统内部错误、资源耗尽错误等。由于在些种情况下,除了通知用户并试图终止程序外几乎是不能做其他任何处理的,因此,不应该抛出这种类型的错误,而是直接让程序中断。 • Exception类定义可能遇到的轻微错误,分为继承RuntimeException类的异常和非继承RuntimeException类的异常。这时,可以写代码来处理异常并继续程序执行,而不是让程序中断。

  7. 异常和异常类 图8-1 Java异常继承关系示意图

  8. 异常处理 • 引例中,异常发生后,Java在运行时将这个异常抛出,可是抛出后没有程序代码去捕捉它,所以程序被中断。 • 如果添加捕捉异常的程序代码,则可针对不同的异常做妥善的处理。 • try{} • catch(){} • finally{}

  9. 异常处理示例 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 printed No,I mean it! This is always printed HELLO WORLD!! This is always printed Re-setting Index Value This is always printed

  10. 异常处理方法 • 通过上例发现,当一个方法被调用时如果发生异常,必须采取相应措施解决出现的问题,即进行异常处理。有两种方法解决以上问题。 • 第一,通过try-catch语句捕获异常,并调用方法处理它。 • 第二,被调用的方法自己不处理异常,该异常将被抛回到调用它的方法中。它是使用throws来实现的,例如,public void troublesome() throws IOException • 关键字throws之后是troublesome()出现的所有异常列表,该方法可以抛回IOException到调用它的程序中。如果有多个异常被抛出,可以使用逗号分开的列表列出所有的异常类。 声明异常

  11. 声明异常示例 运行结果: C:\java>java Ex8_3 求平方根: 4 2.0 C:\java>java Ex8_3 求平方根: -4 输入的数是负数,不能求平方根 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("输入的数是负数,不能求平方根"); } } } • 程序分析:在这个程序中,定义的异常类继承了Exception异常类。在test()方法首部声明了异常Ex8_3异常,并在其方法中用throw子句指定了可能抛出的异常。

  12. 捕获异常 • 通过例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子句所声明类的异常,那么该方法会立即退出。

  13. 捕获异常(续) • 这种方式将所有的代码都置入一个try块内集中处理,因此大量不同的方法调用可能生成相同的异常,只需要一个控制器就可以捕获处理。当然,如果自己捕获并处理异常,就不用在方法头部用throws语句来声明异常了。 • 我们已经知道,当异常产生时,方法的执行流程非线性方式执行,甚至在没有匹配catch子句时,可能从方法中过早退出。但有时,无论异常发生还是被捕获,都希望有些语句必须执行。例如,首先要打开文件,接着对文件进行处理,然后关闭文件,当然不希望将关闭文件的这段代码由异常处理来进行。finally语句就提供了这种问题的解决办法

  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,然后抛出已经捕获的异常。这就是重新抛出异常的最常见的原因。

  15. 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 }

  16. finally子句(续) • finally子句是必须执行的,无论程序是否捕获到异常。当程序中出现finally子句时,执行流程分四种情况: 1. 方法不抛出任何异常。程序将执行try块里的所有代码,然后执行finally子句的代码,再执行后续代码。 2. 方法抛出catch子句能够捕获的异常,而且catch子句没有重新抛出异常。此时,程序将执行try块中的代码,直到抛出异常,然后try块的剩余代码被跳过,执行匹配的catch子句代码,接着执行finally子句的代码,再执行后续代码 3. 方法抛出catch子句能够捕获的异常,而且catch子句重新抛出异常。执行过程与第2种情况相同,只是最后异常被重新抛出。 4. 方法抛出不能被catch子句捕获的异常。此时,程序先执行try块里的代码,直到抛出异常,然后跳过try块的剩余代码,执行finally子句的代码,再将异常抛出给该方法的调用者。

  17. 抛出异常 • Java程序在运行时如果引发了一个可以识别的错误,就会产生一个与该错误相对应的异常类的对象,这个过程称作异常的抛出,实际是相应异常类的实例的抛出。根据异常类的不同,抛出异常的方式也有所不同 • 系统自动抛出的异常——所有的系统定义的运行错误异常 • 语句抛出的异常 用户自定义的异常不可能依靠系统自动抛出,必须用throw语句明确地抛出一个异常。首先,必须知道什么情况下产生了某种异常对应的错误,然后为这个异常类创建一个实例,最后用throw语句抛出。下面是throw语句的常用格式: 返回类型 方法名(参数列表)throws要抛出的异常类名列表{ …… throw异常实例; …… }

  18. 抛出异常(续) • 这样定义方法后,可通知所有要调用这个方法的上层方法,准备接受和处理它在运行中可能会抛出的异常。 • 一般情况下,这种抛出语句应在某种条件满足下执行,例如, void MyMethod()throws MyException{ //可能在程序中抛出MyException异常 …… if(i>100) throw(new MyException()); …… } • 如果方法中的throw语句不止一个,则应该在方法头throws后列出所有可能的异常。

  19. 抛出异常(续) • 若某个方法MyMethod可能产生Exception1、Exception2和Exception3 三种异常,而它们又都是Super_Exception类的子类,则应在相应的方法中声明可能抛出的异常类,语句如下: void MyMethod() throws Exception1,Exception2,Exception3 { …… //可能抛出这三个异常 } • 还可以只简单地声明抛出Super_Exception,下面这种方式和上面的是等价的。 void MyMethod() throws Super_Exception{ ……//可能抛出这三个异常的父类 }

  20. 抛出异常(续) • 在Java语言中如果调用了一个可能产生异常的方法,如果调用方法不处理这个异常,则在调用方法中要对这个异常类进行声明,如下面代码: void YourMethod() throws Super_Exception{ …… MyMethod();//调用了可能会抛出异常的方法 …… } • Java语言要求所有用throws关键字声明的类和用throw抛出的对象必须是Throwable类或其子类。但如果试图抛出一个不可抛出的异常,Java编译器将会报错。

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

  22. 重新抛出异常示例 // 一个重新抛出异常的示例 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)

  23. 自定义异常 • 为了适应各种异常,Java语言可以通过继承的方式编写自己的异常类。因为所有的异常类均继承自Exception类,所以自定义类也必须继承这个类。自定义异常类的语法如下, class 异常类名 extends Exception { 类体 } • 在自定义异常类里通过编写新的方法来处理相关的异常,甚至可以不编写任何语句也可正常工作,因为Exception类已提供相当丰富的方法。

  24. 自定义异常示例 // 创建自己的异常类。 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语句来抛出自定义异常。

  25. 自定义异常类及其使用示例 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 MyException MyException: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!”信息和异常发生地点的方法调用的顺序。

  26. 多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()); }

  27. 多catch语句使用示例(续) 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); } } 运行结果: 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语句,发现与抛出的异常类型匹配时就执行那一段处理代码,而其余的不会被执行。

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

  29. 本章小结 • 异常处理是成功设计一个Java程序的保证。本章介绍了Java语言中异常和异常类的概念,讨论了异常处理的方法。 • 异常是程序运行时出现的非正常情况,可以是由于程序设计本身的错误,也有可能是由于运行中出现了不可解决的问题造成了异常。异常往往会导致程序运行失败或者程序运行的终止。 • 在Java语言中提供了一系列的异常处理方法,程序中出现的异常都是以某个异常类的实例(对象)形式存在。

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

  31. 本章小结 • 在Java中可以通过继承Exception类创建自定义异常类,一旦创建了自定义异常类,则该异常类的使用方法等同于系统异常类。 • 异常处理可以提高程序的健壮性,学会如何处理异常,如何在程序中应用异常处理机制来提高所设计程序的健壮性,设计出更完善的程序将是学习Java编程中的一个非常关键的问题。

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

More Related