错误与异常

软件系统质量要求
• 软件系统不仅要满足用户的功能需求,还应具有可靠性、稳定性和容错性。
• 在用户操作出现错误时,或遇到不可抗拒的干扰时,软件系统也不能放弃,而必须尽最大努力排除错误继续运行。

错误与异常
• 错误
- 错误(error)是指程序遇到非常严重的不正常状态,不能简单地恢复执行。
- 一般是指在运行时遇到的硬件或操作系统的错误,如内存溢出、操作系统出错、虚拟机出错等。
- 错误对于程序而言是致命性的,错误将导致程序无法运行。
- 错误由程序本身不能处理,只能依靠外界干预,否则会一直处于非正常状态。
• 异常
- 异常(exception)指非致命性错误。
- 一般指在运行程序时硬件和操作系统是正常的,而程序遇到的运行错。如:
整数进行除法运算时除数为0,
操作数超出数据范围,
打开一个文件时发现文件不存在,
网络连接中断等。
- 异常会导致应用程序非正常终止。
• Java语言提供异常处理机制
- 使应用程序自身能够捕获异常,并且能够处理异常。
- 由异常处理部分调整应用程序运行状态,使应用程序仍可继续运行。

错误与异常的分类

• Java类库提供了许多处理错误和异常的类,主要分为两大部分:Error类和Exception类。
- Error类是错误类,由Java虚拟机生成并抛给系统,如内存溢出错误、栈溢出错误、动态链接错误等。例如:
当运行某一个类时,如果没有main()方法,产生错误NoClassDefFoundError。
当使用new分配内存空间时,如果没有可用内存,则产生内存溢出错误:OutOfMemoryError。
- Exception类是异常类,由Java应用程序捕获和处理。
每一种异常对应Exception类的一个子类。
异常对象中包含错误的位置和特征等信息。
Java预定义了多种通用的异常类。
image.png

捕获异常并处理

Java异常处理的方式有两种:
• 捕获异常并处理
• 抛出异常
try-catch-finally语句,格式如下:

  1. try
  2. {
  3. //可能会产生异常的语句序列
  4. }
  5. catch (ExceptionType1 e1)
  6. {
  7. // 异常处理代码,捕获到该类型异常后进行处理
  8. }
  9. catch (ExceptionTypeN eN)
  10. {
  11. //异常处理代码,捕获到该类型异常后进行处理
  12. }
  13. finally
  14. {
  15. //语句序列,无论是否捕获到异常都必须执行的语句
  16. }

注意:
• 一旦发生异常,将自动匹配catch子句中的异常类型,找到相应的catch子句后,执行该catch语句。
• 如果没有捕获到异常,则所有的catch语句将不执行。
• Finally 语句块总会被执行,无论是否有异常发生,或是否捕获到异常。
• Finally 语句块是可选项。
• Catch 和 finally 可以只有其中一项或两项都有,但必须至少有一项。

例:异常处理程序,使用try-catch-finally语句进行异常处理。

  1. public class TryCatchFinally
  2. {
  3. public static void main (String args[])
  4. {
  5. int i=0;
  6. int a[]={1,2,3,4,5};
  7. for(i=0;i<6;i++)
  8. {
  9. try
  10. {
  11. System.out.print("a["+i+"]/"+i+"="+(a[i]/i));
  12. }
  13. catch(ArrayIndexOutOfBoundsException e)
  14. {
  15. System.out.print("捕获到数组下标越界异常!");
  16. }
  17. catch(ArithmeticException e)
  18. {
  19. System.out.print("捕获到算术异常!");
  20. }
  21. catch(Exception e)
  22. {
  23. //输出异常信息
  24. System.out.print("捕获"+e.getMessage()+"异常!");
  25. }
  26. finally
  27. {
  28. System.out.println("i="+i);
  29. }
  30. }
  31. }
  32. }

image.png

抛出异常

• 将可能发生的异常转移到上一层调用该成员方法的方法中,就是抛出异常。
• 发生异常的方法不处理该异常,而是由上一层处理。
• 抛出异常有2种子句:
1. throw 异常对象,
2. throws子句。

  1. throw
    throw的语法格式如下:

    1. throw 异常对象;

    其中:
    • throw是关键字,用于抛出异常,由try语句捕获并处理。
    • 异常对象是程序创建的指定异常类对象。

  2. throws
    假如一个方法的方法体会产生异常,而该方法体中不想处理或不能处理该异常,则可以在方法声明时,采用throws子句声明该方法,将异常抛出。
    throws的语法格式如下:

    1. [修饰符] 返回类型 方法名(参数列表) throws 异常类型1, 异常类型2,… { // 方法体 }
    2. public void set(int age) throws Exception
    3. {
    4. if (age>0 && age<150)
    5. this.age = age;
    6. else
    7. throw new Exception("年龄无效"+age);
    8. }

    自定义异常类

    • 在进行Java应用程序设计时,可以使用类库中已经定义好的异常类。
    • 系统预定义的类库有时候不能满足用户需要时,程序员编写应用程序时可以自定义需要的异常类。
    • 自定义异常类必须继承已有的异常类,即用户自定义的异常类都必须直接或间接地是Exception类的子类。

    例题

    例:自定义年龄异常类
    // AgeException.java / 功能简介:声明自定义异常类。 / public class AgeException extends Exception //无效年龄异常类 { public AgeException(String s){ super(s); //调用父类的构造方法 } public AgeException(){ this(“”); } }
    例:自定义异常类的使用

    1. // Person1.java /* 自定义异常类的使用。 */
    2. public class Person1
    3. {
    4. private String name; //姓名
    5. private int age; //年龄
    6. public Person1(String name,int age) throws AgeException
    7. {
    8. this.set(name);
    9. this.set(age);
    10. }
    11. public void set(String name)
    12. {
    13. if (name==null || name=="")
    14. this.name = "姓名未知";
    15. else
    16. this.name = name;
    17. }
    18. public void set(int age) throws AgeException
    19. {
    20. if (age>=0 && age<150)
    21. this.age = age;
    22. else
    23. throw new AgeException("无效年龄"+age);
    24. }
    25. public void set(String name, int age) throws AgeException
    26. {
    27. this.set(name);
    28. this.set(age);
    29. }
    30. public String toString()
    31. {
    32. return this.name+","+this.age+"岁";
    33. }
    34. public void print()
    35. {
    36. System.out.println(this.toString());
    37. }
    38. public static void main(String args[])
    39. {
    40. Person1 p1=null;
    41. Person1 p2=null;
    42. try
    43. {
    44. //调用声明抛出异常的方法,必须写在try语句中,否则编译不通过
    45. p1 = new Person1("小李子",36);
    46. p1.set(121);
    47. p2 = new Person1("小王",20);
    48. p2.set(200);
    49. }
    50. catch(AgeException e)
    51. {
    52. //捕获自定义异常类,而非Exception类
    53. e.printStackTrace();//显示异常栈跟踪信息
    54. }
    55. finally
    56. {
    57. p1.print();
    58. p2.print();
    59. }
    60. }
    61. }

    程序运行结果如下图6-5所示。
    image.png
    图6-5 程序运行结果

    总结:

    1)自定义类异常类AgeException,
    2)发生异常,捕获异常的方法,用了throws子句,抛出异常。
    3)抛出的异常由上一级处理。即谁用谁处理。