Logo

郎哥编程

程序主动引发异常

2021-07-03 194

学习目标:前面学习了如何捕获Java运行时由系统引发的异常,如果想在程序中明确地引发异常,则需要用到throw和throws语句。

throw语句

throw语句通常用在方法体中,并且抛出一个异常对象。程序在执行到throw语句时立即停止,它后面的语句都不执行。

throw语句的语法规则如下:

throw ThrowableInstance

其中,ThrowableInstance是Throwable类型或Throwable子类类型的一个对象。通过参数传递到catch子句,或者用new语句来创建一个实例。

案例8:建立ThrowDemo类,使用throw语句抛出异常。

在PUnit9项目新建throwdemo包,在throwdemo包下新建ThrowDemo类。代码如下:

package throwdemo;
 
public class ThrowDemo {
    public static void main(String[] args) {
        demoproc();
    }
 
    static void demoproc() {
        try {
            // 使用throw抛出异常
            throw new NullPointerException("这是一个自己抛出的异常");
        } catch(NullPointerException e) {
            System.out.println("处理自己抛出的异常");
            // 再次抛出异常
            throw e;
        }
    }
 
}

在demoproc()方法的try语句块中,使用throw语句抛出一个NullPointerException异常,该异常被demoproc()方法的catch语句捕获,执行catch语句的代码,首先输出“处理自己抛出的异常”语句到控制台,随后再次应用throw语句抛出NullPointerException异常,抛出的异常被main方法的catch语句捕获,输出异常信息。输出结果如下图所示:

11.png

语句“throw new NullPointerExceptio()”,用new来构造一个NullPointerException实例。所有的Java内置的运行时异常类有两个构造函数:一个没有参数,一个带有一个字符串参数。当用到第二种形式时,参数指定描述异常的字符串。如果对象用作 print( )或println( )的参数时,该字符串被显示。也可以通过调用gtMessage( )来实现,getMessage( )是由Throwable定义的。

throws语句

如果一个方法可以引发异常,而它本身并不对该异常进行处理,那么该方法必须将这个异常抛给调用者可以使程序能够继续执行下去,这时候就要用到throws语句。

throws语句的语法规则如下:

returnType methodName() throws ExceptionType1, ExceptionType2,….
{
   ……..//方法体
}

在方法体中可以是引发异常列表中的任何一种异常及其子类型的异常。throws用来声明一个方法可能会抛出所有的异常,它跟在方法名称的后面。如果有多个异常,则使用逗号将其分开。调用者调用该方法时,必须要处理这个异常,一般情况下由调用此方法的类来处理。

案例9:建立ThrowsDemo类,使用throws语句抛出异常。

在throwdemo包下新建ThrowsDemo类。代码如下:

package throwdemo;
 
public class ThrowsDemo {
    public static void main(String[] args) {
        try {
            testDemo();
        } catch (NumberFormatException e) {
            System.err.println("非数据类型不能强制类型转换。");
        }
 
    }
 
    public static void testDemo() throws NumberFormatException {
        String s = "abc";
        System.out.println(Double.parseDouble(s));
    }
 
}

如果方法声明后有throws语句,则在此方法被调用时,需要在调用方法中用try和catch进行异常捕获,如果不捕获异常,则需要在调用方法中使用throws语句将异常抛出。

当覆盖抛出异常的方法时,覆盖方法仅需要声明异常的同类或子类。例如,如果父类方法抛出IOException,则覆盖方法可以抛出IOException、FileNotFoundException(IOException的子类),但不可以抛出Exception(IOException的父类)。

throw和throws语句的组合应用

在实际应用中,一般都需要throw和throws语句组合应用,就是在捕获异常后,抛出一个明确的异常给调用者。

案例10:新建一个类,在类中添加一个两数相除的方法,方法要求在操作之前必须打印“运算开始”的信息,结束之后必须打印“计算结束”的信息。

在throwdemo包下新建ThrowAndThrowsDemo类。代码如下:

package throwdemo;
 
public class ThrowAndThrowsDemo {
    public static void main(String[] args) {
        try {
            System.out.println("除法操作:" + div(10, 0));
        } catch (Exception e) {
            System.out.println("异常产生:" + e);
        }
 
    }
 
    public static int div(int num1,int num2) throws Exception{
        // 定义除法操作,如果有异常,则交给被调用处处理
        System.out.println("***** 计算开始 *****") ;
        int temp = 0 ;    // 定义局部变量
        try{
            // 计算,但是此处有可能出现异常
            temp = num1 / num2 ;
        }catch(Exception e){
            throw e;
        }finally{
            // 不管是否有异常,都要执行统一出口
            System.out.println("***** 计算结束 *****") ;
        }
        return temp ;
    }
 
}

代码中div方法名称后面使用了throws语句抛出Exception异常,main方法是div方法的调用者,因此能够捕获throws语句抛出的异常。finally语句块是不管异常发生与否,都要执行的代码块,下一课会详细讲解。

throw语句是编写在方法之内的,而throws语句是用在方法名称之后的。在同一个方法中使用throw和throws时要注意,throws抛出的类型范围要比throw抛出的对象范围大才可以。

显示异常信息

前面学习了各种异常类及异常语句的用法。在实际编程过程中,还需要显示导致异常出现的信息,方便程序员根据给出的异常信息查找程序错误。异常类提供了输出异常信息的两个方法:getMessage方法和printStackTrace方法。

getMessage方法

用于获取异常的详细消息字符串。

printStackTrace方法

输出Throwable对象的堆栈跟踪信息到控制台。

在catch中声明的异常对象catch(Exception ex)封装了异常事件发生的信息,在catch语句块中可以使用这个对象的getMessage方法获取错误信息。

getMessage的使用方法示例如下:

 public static void main(String[] args) {  
    try {  
        int  i = 12 / 0;  
    } catch (Exception e) {  
        System.out.println(e.getMessage());  
 }

运行代码,因为被零除,所以发生异常,输出“/  by  zero”。

printStackTrace的用法示例如下:
    public static void main(String[] args) {
        try {  
            int  i = 12 / 0;  
        } catch (Exception e) {  
            e.printStackTrace();
        }
}

使用printStackTrace方法可以获取异常的具体类型,这样就可以在使用throw时抛出一个确定的异常类型。

异常的分类

从编程角度考虑,可以将异常分为以下几种。

(1)非受检异常

非受检异常是指编译器不要求强制处置的异常。一般是指因设计或实现方式不当而导致的问题。也可以说,是程序员的原因导致的,是本来可以避免发生的情况。

java.lang.RuntimeException类及其子类都是非受检异常。具体如下:

ava.lang.ClassCastException:

错误的类型转换异常。

java.lang.ArrayIndexOutOfBoundsException:

组下标越界异常。

java.lang.NullPointException:

空指针访问异常。

java.lang.ArithmeticException:

除零溢出异常。

如果事先检查数组元素下标,保证其不超出数组长度,ArrayIndexOutOfBoundsException异常就不会抛出;再如,先检查并确保一个引用类型变量值不为NULL,然后再访问其属性和方法,那么,NullPointException异常就不会抛出。因此,如果程序设计良好并且正确实现,这类异常就不会发生,所以通常也不会处理这类异常。

(2)受检异常

受检异常是指编译器要求必须处置的异常,即程序在运行时由于外界因素造成的一般性异常,具体如下:

java.lang.ClassNotFoundExeption:

没有找到具有指定名称的类异常。

java.lang.FileNotFoundException:

访问不存在的文件异常。

java.lang.IO Exception:

操作文件时发生的异常。

java.sql.SQL Exception:

操作数据库时发生的异常。

Java编译器要求Java程序必须捕获或声明所有受检异常。如FileNotFoundException、IO Exception等。因为,对于这类异常来说,如果程序不进行处理,可能会带来意向不到的结果。而非受检异常可以不做处理,因为这类异常很普遍,若全部处理可能会对程序的可读性和运行效率产生影响。

 

代码在线纠错(通义千问 qwen-max)

支持粘贴多个代码文件,提交后由阿里云通义千问自动分析代码漏洞、语法错误、逻辑问题并给出修改建议。
您已解锁 AI 代码纠错功能,可正常使用!

评论区

登录 后发表评论
暂无评论