• 1. 第5章 异常处理实际运行的软件系统——不仅具有满足用户需求的强大功能,还必须具有高度的可靠性、稳定性和容错性。Java语言——语法体系是严密的,语法检查是严格的, 不仅在编译时能够检查出所有语法错误, 而且在运行时能够捕获到所有运行时错误;Java的异常处理提供对运行时错误的语言级处理机制; Java的内存自动管理提供内存资源使用的安全性。1
  • 2. 第5章 异常处理异常处理——捕获和处理运行时错误的一种机制。异常处理机制使程序具有处理错误的能力,即使发生了运行时错误,应用程序能够捕获异常并及时处理异常,使程序从运行错误中很好地恢复并继续运行,而不会导致程序运行非正常终止。2
  • 3. 第5章 异常处理5.1 异常处理基础 5.2 异常处理措施3
  • 4. 5.1 异常处理基础5.1.1 异常处理机制的必要性 5.1.2 错误和异常4
  • 5. 面向过程语言——提供的错误处理方式是不完全的,不能保证 及时发现错误并制止错误的蔓延。例如:C语言在默认情况下是不进行数据范围检查的,面向过程语言—没有提供对运行时错误的防范和处理机制,只 能任凭错误的产生而导致程序运行中断。例如:输入数据格式错、文件不存在、无法连接数据库、 网络连接中断等。面向过程语言提供的错误处理方式显然不能满足 面向对象程序设计的要求。5.1.1 异常处理机制的必要性1. 面向过程语言错误处理方式的缺陷5
  • 6. 面向对象程序设计思想——程序的正确性、可靠性和稳定性比 程序效率更重要。面向对象语言——提供语言级的错误防范和处理机制,即异常 处理机制,它提供全面的、强有力的错误检查与处理方法。异常处理机制——将运行时错误封装成若干错误类和异常类, 并提供异常处理语句用于在程序中实现对运 行时错误的发现和及时处理,是一种对异常 进行事后处理的机制。 5.1.1 异常处理机制的必要性2. 面向对象语言的异常处理思想6
  • 7. 异常处理机制的优越性体现在以下两方面: 从语法上看,异常处理语句将程序正常代码与错误处理代码 分开,使程序结构清晰,算法重点突出,可读性强。从运行效果看,异常处理语句使程序具有处理错误的能力。 即使发生了运行错,应用程序能够捕获异常并及时处理异常, 使程序从运行错误中很好地恢复并继续运行,而不会导致程序 运行非正常终止。而且,如果当前方法没有能力处理异常,还 可以将异常转交给调用者处理。5.1.1 异常处理机制的必要性2. 面向对象语言的异常处理思想7
  • 8. Java语言提供严密的语法规则,弥补了C++语言的不严密之处。Java在编译和运行时严格检查错误,能够发现所有语法错和 运行错,能够发现C++不能发现的错误。例如:整数和字符等不同类型的数据不能进行运算等;Java放弃了C++中全程变量、goto语句、宏定义、全局函数以 及结构、联合和指针数据类型,减少了潜在的程序错误。 例如:不能使用指针对指定地址的内存区域进行操作等。 例如:数组下标越界错误等。 5.1.1 异常处理机制的必要性3. Java语言是安全的8
  • 9. 3. Java语言是安全的 Java提供异常处理机制,使程序能够捕获并处理运行错, 从而保证Java程序运行的可靠性和容错性。Java提供内存自动管理方式,能够自动跟踪程序使用的所有 内存资源,并且当内存资源不再被使用时能够自动回收,不 需要在程序中写释放内存语句,既减少了程序员的工作量, 又提高了可靠性和安全性。5.1.1 异常处理机制的必要性9
  • 10. 1. 错误 (error) 错误—指程序运行时遇到的硬件错误、操作系统的错误、 其他软件错误或操作错误。 错误对于程序而言是致命的,将导致程序无法运行,而且 程序本身不能处理错误,只能依靠外界干预,否则会一直 处于非正常状态。例如:没有找到.class文件; .class文件中没有main()方法等。5.1.2 错误和异常10
  • 11. Java.lang.Error是错误类,当产生错误时,由Java虚拟机生 成并抛出Error类对象。例如:当运行没有main()方法的类时,则产生类定义未找到错误 (noClassDefFoundError); 当使用new分配内存时,如果没有可用内存,则产生内存 溢出错误 (OutOfMemoryError);5.1.2 错误和异常1. 错误 (error) 11
  • 12. 2. 异常(exception) 异常—指在硬件和操作系统正常时,程序遇到的运行错。 异常对于程序而言是非致命的,虽然异常会导致程序非正 常终止,但Java的异常处理机制使程序自身能够捕获和处 理异常,由异常处理代码调整程序运行方向,使程序仍可 继续运行。例如:整数进行除法运算时除数为0; 操作数超出数据范围; 打开一个文件时发现文件不存在; 网络连接中断等。5.1.2 错误和异常12
  • 13. Java.lang.Exception是异常类,Exception对象是Java程序捕获 和处理的对象。每一种异常对应于Exception类的一个子类, 异常对象中包含错误的位置和特征信息。Java定义的异常类主要分为运行异常和非运行异常。注:Exception类和Error类都是Throwable类的子类。 —P130图5.15.1.2 错误和异常2. 异常(exception) 运行异常—指由程序本身错误引发的异常,这类异常程序设计时 大多可以避免; 非运行异常—指由程序运行环境错误引发的异常,这类异常必 须捕获并处理。 13
  • 14. Throwable类的部分声明如下: public class Throwable implements Serializable { public Throwable ( ) public Throwable (String message) public String getMessage ( ) //获得异常信息 public String toString ( ) //获得异常对象的描述信息 public void printStackTrace ( ) //显示异常栈跟踪信息 }public class Exception extends Throwable { public Exception () public Exception (String s) }5.1.2 错误和异常14
  • 15. 运行异常都是RuntimeException 的子类。 3. RuntimeException运行异常类5.1.2 错误和异常(1) 算术异常ArithmeticException 当进行整数除法或取余运算时,如果除数为0,则会产生。例如: System.out.println(“”+(3/0)); //产生算术异常 运行时错误信息如下: Exception in thread “main” java.lang.ArithmeticException:/by zero at Division_by_zero.main(Division_by_zero.java:7)对于下列浮点除法中除数为0的语义错,Java在运行时没有发现 错误,没有抛出异常,运算结果为无穷大Infinity。 System.out.println(“”+(3/0.0)); //运算结果为Infinity15
  • 16. (2) 空对象异常NullPointerException 例如: int a[]=null; a[0]=1; //对空数组中的元素进行操作,产生空对象异常 String str=null System.out.println(str.length()); //通过空对象调用方法,产生空对象异常3. RuntimeException运行异常类5.1.2 错误和异常当对空数组中元素进行操作,或通过空对象调用方法时,则产生。16
  • 17. (3) 类型强制转换异常ClassCastException 当进行类型强制转换时且遇到不能进行的转换操作时,则产生。例如: Object obj=new Object( ); String str=(String) obj; //obj不能转换成String对象,产生类型强制转换异常 (4) 负数组长度异常NegativeArraySizeException 当申请数组的存储空间且指定数组长度是负数时,则产生。例如: int a[]=new int[-1]; //产生负数组长度异常3. RuntimeException运行异常类5.1.2 错误和异常17
  • 18. (5) 数组下标越界异常ArrayIndexOutOfBoundsException 当通过越界的下标访问数组元素时,则产生。例如: int a[]={1,2,3,4} for ( int i=0;i<5;i++) System.out.println(“a[”+i+”]=”+a[i]); //产生数组下标越界异常3. RuntimeException运行异常类5.1.2 错误和异常(6) 字符串序号越界异常StringIndexOutOfBoundsException 当指定字符串中字符的序号越界时,则产生。例如: “abc”.charAt(-1) //产生字符串序号越界异常18
  • 19. (7) 数值格式异常NumberFormatException 当将字符串转换成数值且给定字符串不符合数值格式时,则产生。例如: int i=Integer.parseInt(“123a”); //不能将字符串转换成整数,产生异常 double x=Double.parseDouble(“123.45x”) ; //不能将字符串转换成浮点数,产生异常3. RuntimeException运行异常类5.1.2 错误和异常例如: public static int parseInt (String s) throws NumberFormatException //将字符串s转换为int整数 public static double parseDouble (String s) throws NumberFormatException //将字符串s转换为浮点数19
  • 20. 4. 程序对错误与异常的三种处理方式(1) 程序不能处理错误 (2) 程序应避免而不捕获的异常 内存溢出、栈溢出等错误,由系统进行处理,Java程序本 身不能对错误进行处理。对于程序能够遇见的异常,程序应该考虑周到进行事先处理, 尽量避免发生异常。 例如:进行除法运算时,判断除数是否为0并给出解决办法, 避免发生除数为0的异常; 使数组下标在0-a.length-1之间变化,避免发生下标 越界异常。5.1.2 错误和异常20
  • 21. 4. 程序对错误与异常的三种处理方式(3) 必须捕获的异常 对于程序无法预见的、由特殊环境错误造成的异常,必须 进行捕获和处理,从而保证程序正常运行,保证程序的可 靠性和安全性。 例如:文件没找到、网络连接中断等。5.1.2 错误和异常21
  • 22. 一个异常对象经历抛出、捕获及处理过程:抛出(throw)异常—创建一个异常类对象的过程;捕获(catch)异常—获得异常对象的过程;处理异常—对异常对象执行相应操作的过程;注:异常对象由捕获它的语句进行处理。5.2 异常处理措施22
  • 23. 5.2 异常处理措施5.2.1 异常处理语句 5.2.2 抛出异常 5.2.3 自定义异常类23
  • 24. 1.异常处理语句语法 5.2.1 异常处理语句 try { 语句1 //存在潜在异常的代码 } catch(异常类 异常对象) { // 用于捕获并处理指定类型的异常对象,参数是一个异常对象e, 其类型必须是Exception类及其子类。 语句2 //捕获到异常并进行处理的代码 } finally //子句可以省略 { 语句3 //最后必须执行的代码,无论是否捕获到异常 }24
  • 25. 5.2.1 异常处理语句 例如:调用parseInt()方法的异常处理语句如下:String str = "123a"; try { int i = Integer.parseInt(str); //调用声明抛出异常的方法 } catch (NumberFormatException e) //捕获parseInt()方法声明的异常对象 { System.out.println(str+"字符串不能转换为整数"); } catch (Exception e) //捕获所有异常对象 { e.printStackTrace(); //显示异常栈跟踪信息 }25
  • 26. 5.2.1 异常处理语句 2. try语句执行流程图5.2 异常处理语句的执行流程26
  • 27. 5.2.1 异常处理语句 2. try语句执行流程(1) 正常情况下(即没有产生异常时) (2) 捕获异常并处理 首先执行try子句中的语句序列; 若没有产生异常则跳过catch子句, 再执行finally子句中的语句序列; 然后继续执行后面的语句。catch子句说明: catch语句可以有多个,分别处理不同类的异常。27
  • 28. 5.2.1 异常处理语句 (2) 捕获异常并处理 执行try子句出现运行错时,Java抛出一个异常对象e,交由 与e匹配的catch子句捕获并处理,即e是该catch子句参数异常类或 其子类的实例。“e instanceof 异常类”返回true。抛出的异常对象和catch子句中异常类的关系: Java按照多个catch子句的书写次序从上向下依次查找每个 catch子句中的异常类,一旦异常对象e是某个catch子句的异常类 或其子类实例,则被该catch子句捕获并处理,一个异常对象只能 被一个catch子句捕获,之后Java将自动清除该异常对象,其它 catch子句或外层的try语句将不能再捕获该异常对象。=>多个catch子句需要按异常类从子类到父类的次序依次排列。28
  • 29. 5.2.1 异常处理语句 (2) 捕获异常并处理 如果所有catch子句都没有捕获e,则e将由Java虚拟机捕获并 处理,导致程序运行终止,就像没有使用try语句。 => 因此,通常最后一个catch子句的异常类参数声明为Exception, 这样能够保证捕获和处理所有异常对象。2. try语句执行流程29
  • 30. 5.2.1 异常处理语句 (3) 执行finally子句 finally子句中的语句系列是最后必须执行的代码,无论 是否产生异常。 当try子句中的某条语句产生一个异常时,该语句之后的 语句序列都将不会被执行。如果有些语句肯定需要被执行, 不管是否产生了异常,则这些语句需要写在finally子句中。 注:try-catch- finally 语句的结构使正常执行的语句与异常处 理的语句分离,增强了程序的可读性。 2. try语句执行流程30
  • 31. 5.2.1 异常处理语句 【例5.1】求数组元素的平均值。public static double average(int table[]) //求数组元素的平均值 { double sum=0.0; for (int i=0; i
  • 32. ① 避免除数为0的运行错误 average()方法求数组元素平均值,存在空对象异常和 除数为0的潜在错误。 ② 必须处理异常 tointArray()方法采用异常处理语句对产生的运行时 错误进行事后处理③ 采用命令行参数输入数值时要处理异常【例5.1】求数组元素的平均值。5.2.1 异常处理语句 32
  • 33. 1. 抛出自定义异常对象的throw语句 5.2.2 抛出异常 一个异常对象可以由Java虚拟机抛出,也可以由程序主动 抛出。如果程序中存在逻辑错误但不是Java的异常,程序 也可以主动抛出一个异常对象。 Java提供给程序主动抛出异常的语句是throw: throw 异常对象 //<异常对象>是程序创建的指定异常类对象33
  • 34. 1. 抛出自定义异常对象的throw语句 5.2.2 抛出异常 由throw语句抛出的异常也必须由try语句捕获并处理,异常抛出和处理既可以在一个方法中,也可以分别在不同的方法中。例如: public void set (int year, int month, int day) //设置日期 { if (month<1 ‖ month>12) throw new Exception(“月份错误”); …… //其他语句省略 }34
  • 35. 5.2.2 抛出异常 2. 方法声明抛出异常的throws子句 如果一个方法将产生异常,而该方法不想处理或不能处 理该异常,则可以在方法声明时,采用throws子句声明该方法 将抛出异常。 [修饰符] 返回值类型 方法([参数列表]) [throws 异常类] //<异常类>是方法要抛出的异常类,可以声明多个 例如:如果set()方法内没有处理异常,则: public void set (int year, int month, int day) throws Exception35
  • 36. 5.2.2 抛出异常 set()方法抛出的异常,由该方法的调用者处理。如果调用 者也无法处理,可以声明再将该异常抛出。 例如,以下MyDate构造方法调用set()方法,但它无法处理 异常,再声明抛出:public MyDate(int year, int month, int day)throws Exception { this.set (year,month,day); }2. 方法声明抛出异常的throws子句 36
  • 37. 5.2.2 抛出异常 throws子句的作用是:声明方法抛出指定异常,则方法的 调用者必须捕获并处理该指定异常,这样实现了异常对象在 方法之间逐级向上传递。2. 方法声明抛出异常的throws子句 public static void main(String args[]) throws Exception { System.out.println(new MyDate(2009,1,1).toString); }同理,如果main()方法中调用声明抛出异常的方法而无法处 理相应异常,则同样可声明main()方法抛出异常如下:注:main()方法抛出的异常由Java虚拟机捕获,处理结果是终止 程序运行。37
  • 38. 5.2.3 自定义异常类 前述set()方法通过throw语句抛出的Exception异常,只能在以 下catch子句中被捕获: catch (Exception e) { if (e.toString().equals(“月份错误”)) //e是Exception异常对象 } 当Java提供的异常类不能满足需要时,程序需要对自己抛出 的异常类进行特殊处理,则可以自定义异常类,由catch子句捕 获并处理。自定义的异常类应该是Exception的子类。38
  • 39. 5.2.3 自定义异常类 【例5.2】日期类的异常处理。 ——演示抛出异常对象语句、方法声明抛出异常和自定义异常 类,演示异常对象在方法及其调用者之间传递。39