1.6 抛出异常

  异常处理学习到现在,所有的异常都是由系统抛出。作为程序员,有时需要手工抛出一个异常,让异常处理程序进行处理。接下来将学习如果使用throw关键字手工抛出异常。

1.6.1 手工抛出异常

  在Java语言中,可以使用throw关键字手工抛出一个异常,手工抛出异常的语法形式为:

  1. throw 异常对象;

  例如,手工抛出一个算数异常的代码为:

  1. throw new ArithmeticException();

  观察下面的代码,通过throw new NullPointerException(“the “);语句,手工抛出了一个空指针异常,指定信息为“the ”。catch语句块对空指针异常进行捕获,输出异常对象e.getMessage()的值(“the ”),程序运行结果如图1.17所示。

  1. public class TestEx15
  2. {
  3. public static void main(String[] args)
  4. {
  5. System.out.print("Now ");
  6. try{
  7. System.out.print("is ");
  8. throw new NullPointerException("the "); //抛出一个空指针异常,指定信息为“the”
  9. //System.out.print("此句不会被执行!");
  10. }catch(NullPointerException e){ //捕获抛出的空指针异常
  11. System.out.print(e.getMessage());
  12. }
  13. System.out.print("time. \n");
  14. }
  15. }

1.6 抛出异常 - 图1


图1.17 手工抛出异常

1.6.2 再次抛出异常

  catch语句捕获到的异常对象e,在catch语句块的处理程序中,可以使用throw e;语句再次将这个异常抛出,以便它能被外部catch语句捕获。再次抛出异常最常见的情况是允许多个程序处理一个异常。例如,需要一个异常处理代码块处理异常的一个方面,另一个异常处理代码块处理另一个方面,则可以在一个异常处理代码块处理完毕之后再次抛出该异常,让另一个异常处理代码块继续进行处理。通过下面的代码可熟悉如何在两个方法中处理同一个异常。

  1. public class TestEx16{
  2. public static void doEx1()
  3. {
  4. try{
  5. String teachers[]={"柳海龙","孙传杰","孙悦"};
  6. for(int i = 0;i < 4;i++){
  7. System.out.println(teachers[i]);
  8. }
  9. }catch(ArrayIndexOutOfBoundsException e) //捕获数组下标越界异常
  10. {
  11. System.out.println("doEx1方法中处理数组下标越界异常!");
  12. throw e; //再次抛出该数组下标越界异常
  13. }
  14. }
  15. public static void main(String[] args)
  16. {
  17. try{
  18. doEx1();
  19. }catch(ArrayIndexOutOfBoundsException e) //再次捕获数组下标越界异常
  20. {
  21. System.out.println("main方法中处理数组下标越界异常!");
  22. }finally{
  23. System.out.println("程序结束!");
  24. }
  25. }
  26. }

  在该段程序中,doEx1()方法中的异常处理代码块捕获并处理了数组下标越界异常,在处理结束后,又将该异常抛出给调用doEx1()方法的main()方法进行异常处理,main()方法中的异常处理代码块又捕获处理了数组下标越界异常。程序运行结果如图1.18所示。

1.6 抛出异常 - 图2


图1.18 再次抛出异常

  数组下标越界异常属于运行时异常,所以main()方法在调用这个需要抛出数组下标越界异常的doEx1()方法时,即使不对这个抛出的异常进行捕获处理,也能编译通过,只是在运行时会抛出异常而已。去掉main()方法中的异常处理程序,只保留对doEx1()方法的调用,编译、运行程序,程序运行结果如图1.19所示。通过程序运行结果可以看出,在doEx1()方法中的捕获处理代码得到了运行,main()方法未捕获处理抛出的异常,所以运行时抛出异常。

1.6 抛出异常 - 图3


图1.19 运行时异常抛出不捕获处理

1.6.3 抛出检查时异常

  前面介绍检查时异常的时候提到过,检查时异常要求程序员必须在程序中对异常进行捕获处理,否则程序不能编译通过。还是刚才的程序结构,只是doEx1()方法里抛出的异常不再是运行时异常,而是检查时异常,会出现什么样的结果呢?程序代码如下:

  1. import java.net.*;
  2. import java.io.*;
  3. public class TestEx17{
  4. public static ServerSocket ss = null;
  5. public static void doEx1()
  6. {
  7. try {
  8. ss = new ServerSocket(5678);
  9. Socket socket = ss.accept();
  10. }catch (IOException e) { //捕获IOException异常
  11. System.out.println("doEx1方法中处理IOException异常!");
  12. throw e; //再次抛出该IOException异常
  13. }
  14. }
  15. public static void main(String[] args)
  16. {
  17. try{
  18. doEx1();
  19. }catch(IOException e) //再次捕获IOException异常
  20. {
  21. System.out.println("main方法中处理IOException异常!");
  22. }finally{
  23. System.out.println("程序结束!");
  24. }
  25. }
  26. }

  编译程序,编译器报错,如图1.20所示。

1.6 抛出异常 - 图4


图1.20 检查时异常抛出不捕获

  仔细查看错误原因,提示为throw e;语句抛出一个检查时异常,必须要对其进行捕捉或声明以便抛出。该程序的目的就是再次抛出该异常,让调用doEx1()方法的main()方法再次进行异常捕获处理,所以如果在doEx1()方法里继续进行捕获则失去了该程序的定义。如何解决这个问题呢?接下来我们通过声明方法抛出异常的方式,处理这个问题。

1.6.4 声明方法抛出异常

  所谓声明方法抛出异常,就是当方法本身不知道或者不愿意处理某个可能抛出的异常时,可以选择用throws关键字将该异常提交给调用该方法的方法进行处理。当这个异常是检查时异常时,该方法必须进行声明,调用该方法的方法必须进行处理或再次声明向外抛出。声明方法抛出异常很简单,需要在方法的参数列表之后,在方法体的大括号前,增加“throws异常列表”进行声明。

  修改前面的代码,在doEx1()后增加throws IOException,声明doEx1()方法可能抛出IOException异常,因为在main()方法中已有对IOException异常的捕获和处理代码,所以程序可以编译通过。

  在此可使用声明方法抛出异常的方式,处理“给孩子们分苹果”的程序中,孩子数输入不能转换为数字的字符时的问题,具体代码如下:

  1. import java.util.*; //InputMismatchException在java.util包下
  2. public class TestEx18{
  3. //抛出InputMismatchException异常,自己不处理,让方法的直接调用者来处理
  4. private static void p() throws InputMismatchException {
  5. int appleNum = 0; //苹果数
  6. int stuNum = 0; //学生数
  7. System.out.println("***现在给孩子们分苹果***");
  8. Scanner input = new Scanner(System.in);
  9. System.out.print("请输入桌子上有几个苹果:");
  10. appleNum = input.nextInt();
  11. System.out.print("请输入班上有几个孩子:");
  12. stuNum = input.nextInt(); //用户输入“abc”,则系统会抛出InputMismatchException异常
  13. System.out.println("班上每个孩子分得多少苹果:" + appleNum/stuNum);
  14. System.out.println("孩子们非常开心!");
  15. }
  16. public static void main(String args[]){
  17. try{
  18. p(); //方法的直接调用者捕获、处理异常
  19. }catch(InputMismatchException e) {
  20. System.out.println("main方法处理InputMismatchException异常");
  21. }
  22. }
  23. }

  p()方法声明该方法可能抛出InputMismatchException异常,调用p()方法的main()方法处理了p()方法中不处理并声明抛出的这个异常。程序运行结果如图1.21所示。

1.6 抛出异常 - 图5


图1.21 声明方法抛出异常