深入学习Java开发简单应用(蓝桥杯软件大赛培训教材-Java方向)
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.6 抛出异常

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

1.6.1 手工抛出异常

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

throw 异常对象;

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

throw new ArithmeticException();

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

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

图1.17 手工抛出异常

1.6.2 再次抛出异常

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

public class TestEx16{
    public static void doEx1()
    {
        try{
        String teachers[]={"柳海龙","孙传杰","孙悦"};
        for(int i = 0;i < 4;i++){
                System.out.println(teachers[i]);
        }
        }catch(ArrayIndexOutOfBoundsException e)     //捕获数组下标越界异常
        {
        System.out.println("doEx1方法中处理数组下标越界异常!");
        throw e;                                     //再次抛出该数组下标越界异常
        }
    }
    public static void main(String[] args)
    {
        try{
        doEx1();
        }catch(ArrayIndexOutOfBoundsException e)     //再次捕获数组下标越界异常
        {
        System.out.println("main方法中处理数组下标越界异常!");
        }finally{
        System.out.println("程序结束!");
        }
    }
}

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

图1.18 再次抛出异常

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

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

1.6.3 抛出检查时异常

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

import java.net.*;
import java.io.*;
public class TestEx17{
    public static ServerSocket ss = null;
    public static void doEx1()
    {
        try {
        ss = new ServerSocket(5678);
        Socket socket = ss.accept();
        }catch(IOException e){        //捕获IOException异常
        System.out.println("doEx1方法中处理IOException异常!");
        throw e;                      //再次抛出该IOException异常
        }
    }
    public static void main(String[] args)
    {
        try{
        doEx1();
        }catch(IOException e)         //再次捕获IOException异常
        {
        System.out.println("main方法中处理IOException异常!");
        }finally{
        System.out.println("程序结束!");
        }
    }
}

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

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

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

1.6.4 声明方法抛出异常

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

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

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

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

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

图1.21 声明方法抛出异常