内容导航

​ 在程序开发中,经常会出现各种突发问题,Java语言作为主流的面向对象开发语言,提供了强大的异常处理机制。Java的所有异常都是会封装到一个类中,在程序错误的时候,及时抛出异常,给程序处理,解决问题的机会,提高了应用的容错性和健壮性。

认识异常

​ 在生活中,异常情况随时都有可能会发生。下面将从生活中的异常过度到程序的异常。

​ 在日常生活中,几乎随时随处可能会发生意外情况,以学校生活为例,在上学的路上发生交通事故或拥堵、教员生病、教室投影仪不能使用,机房网络感染病毒等等,这些都是意外情况。虽然意外情况是偶然事件,但是一但发生就会带来不小麻烦,影响正常的学习生活。同理,在程序中也会发生类似的情况,下面看看程序中的异常。

​ 在程序开发中,程序员虽然会尽量避免错误的发生,但是总会遇到一些不可预期的问题,如除法运算时除数为0,数组下标越界、数据类型不一致、内存不足、栈溢出等,这些就是异常。下面将以代码示列来介绍什么是程序中的异常。

示列1:

package abnormal;

import java.util.Scanner;

/**
 * 计算果商供应量
 */
public class Test {
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入果实的采摘量(公斤):");
        int weight = scanner.nextInt();
        System.out.println("请输入果商数(家):");
        int num = scanner.nextInt();
        System.out.println("每家果商供应量"+weight/num+"公斤水果。");
        System.out.println("欢迎再来,预祝生意兴隆!");
    }

}

运行结果:

请输入果实的采摘量(公斤):
3200
请输入果商数(家):
8
每家果商供应量400公斤水果。
欢迎再来,预祝生意兴隆!

Process finished with exit code 0

因为本程序并没有产生任何异常,所以代码可以全部执行完毕。但有时候,输入错误数据错误会导致程序出错如下例子:

请输入果实的采摘量(公斤):
3200
请输入果商数(家):
0
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at abnormal.Test.main(Test.java:15)
Process finished with exit code 1

在上面的执行过程中,因为输入的果商为0即在运算中除数为0,所以程序出去了异常。另外如果输入的数据类型不是整数,那么也会发生异常,如下例子:

请输入果实的采摘量(公斤):
3200
请输入果商数(家):
八家
Exception in thread "main" java.util.InputMismatchException
    at java.base/java.util.Scanner.throwFor(Scanner.java:939)
    at java.base/java.util.Scanner.next(Scanner.java:1594)
    at java.base/java.util.Scanner.nextInt(Scanner.java:2258)
    at java.base/java.util.Scanner.nextInt(Scanner.java:2212)
    at abnormal.Test.main(Test.java:14)
Process finished with exit code 1

从运行结果可以发现,当异常产生后,会在控制台输入异常提示信息,同时将中止执行异常后面的程序,最后两条输出语句也将不会继续执行。

提示:

关于除数不能为0的说明如下。

​ 在计算机的发展中有两大计算"杀手",一个是断电,另外一个是除数为0,因为除数为0在数学上是无穷大的,对于计算机来说,如果是无穷大,则意味着内存将被全部占满,所以,在程序开发中,务必避免除数为0的情况。

​ 对于一个程序设计人员来说,需要尽量预知所有可能发生的情况,从而保障程序中所有糟糕情况下都能运行,那么应该怎么解决人为造成的问题呢?根据以上产生的错误,可以所有if-else语句进行改造如下

示列2

package abnormal;

import java.util.Scanner;

/**
 * 计算果商供应量(使用if-else语句处理异常)
 */
public class Test2 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.println("请输入果实的采摘量(公斤):");
        int weight = 0;
        if (input.hasNextInt()) {
            weight = input.nextInt();
        }else{
            System.err.println("果实采摘量必须是整数!");
            System.exit(1);
        }
        System.out.println("请输入果商数(家):");
        int num = 0;
        if (input.hasNextInt()){
            num = input.nextInt();
            if (num<=0){
                System.err.println("果商数必须大于零!");
                System.exit(1);
            }
        }else{
            System.out.println("果商数必须输入整数!");
            System.exit(1);
        }
        System.out.println("每家果商供应量" + weight / num + "公斤水果。");
        System.out.println("欢迎再来,预祝生意兴隆!");
    }
}

​ 使用if-else语句进行处理后会发现,程序增加了很多判断和分支。以上例子只考虑了两种可能发生的错误,代码量就会急剧增加了。但实际上,在程序开发中,意外情况是不能穷举的,程序可能发生的异常远远都于程序员能考虑到的,如果每次都在实现真正业务逻辑之前,都需要不厌其烦地考虑各种可能出错的情况,针对各种错误情况给出补救措施,那么是多么乏味的的事情啊!

​ 对于上面的错误处理机制,总结有如下两个缺点。/

  • 无法穷举所有的异常情况

    • 因为受程序员知识的限制,异常情况总比可以考虑到的情况多,总会有"漏网之鱼",所以程序总不够健壮
  • 影响程序可读性,维护难度高

    • 这种错误处理和业务逻辑混杂的代码严重影响程序的可读性,增加程序维护的难度

异常处理机制

​ 在程序设计时,必须考虑到可能发生的异常事件并进行相对应的处理,这样才能保证程序正常运行。

​ JAVA的异常处理机制也秉承着面向对象的基本思想,在Java中,所有的异常都定义为类。除了内置的异常类,Java也可以自定义异常类。此外,Java的异常处理机制也允许自行抛出异常。

​ 那么应该如何使用java异常处理机制自动处理异常呢?

异常处理结果

​ Java针对异常处理提供了 try、catch、finally、throws、throw 五个核心关键字,其中前三个关键字就可以组成常用的异常处理结构,语法如下所示

语法:

try{
    //有可能出去异常的语句
}[catch(异常类型 异常对象){
   //异常处理语句 
}][finally{
    //一定会运行到的语句
}]

​ 其中try语句用于监听,将可能抛出异常的代码放在try语句块内,当try 语句块发生异常时,异常就被抛出;catch语句用来捕获try语句块中抛出的异常;flnally语句块总会被执行,主要用于回收try语句块内打开的资源,如数据库连接、网格连接和磁盘文件。

注意:

​ 以上格式中的catch语句、flnally语句都可选。实际上,这并不是表示catch语句、flnally语句可以同时消失。异常格式的常见组合有try-catchtry-catch-flnallytry-flnally三种。

在程序中处理异常

既然程序员通过自行判断处理异常有诸多不便,那么下面运用Java异常处理机制修改示列1,让程序能够自行判断并处理异常。

使用try-catch语句处理异常

使用try-catch语句处理异常,关键代码如下所示

示列3

package abnormal;

import java.util.Scanner;

/**
 * 使用try-catch语句处理异常
 */
public class Test3 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        try {
            System.out.println("请输入果实的采摘量(公斤):");
            int weight = input.nextInt();
            System.out.println("请输入果商数(家):");
            int num = input.nextInt();
            System.out.println("每家果商供应量" + weight / num + "公斤水果。");
            System.out.println("欢迎再来,预祝生意兴隆!");

        }catch (Exception ex){
            System.err.println("出现错误:采摘量和果商数应为整数,果商数应大于零!");
        }
    }
}

​ 以上程序使用了异常处理语句,当程序程序异常时,异常会被try语句监听到,然后被JVM抛出,被catch语句捕获进行处理,执行catch语句内的异常处理代码,不再需要程序员自行编写if语句进行判断,简化了代码。示列3运行结果如下:

请输入果实的采摘量(公斤):
3200
请输入果商数(家):
0
出现错误:采摘量和果商数应为整数,果商数应大于零!

Process finished with exit code 0

​ 使用Java异常处理机制的目的是帮助成都学院分析异常并解决异常。示列3采用输出错误提示的方式处理异常,不能明确地描述异常类型,不能精确定位问题所在。更好的方法是使用异常类中提供的printStackTrace()方法进行异常信息的完整输出,如下所示

示列4

package abnormal;

import java.util.Scanner;

/**
 * 使用try-catch语句处理异常
 */
public class Test4 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        try {
            System.out.println("请输入果实的采摘量(公斤):");
            int weight = input.nextInt();
            System.out.println("请输入果商数(家):");
            int num = input.nextInt();
            System.out.println("每家果商供应量" + weight / num + "公斤水果。");
            System.out.println("欢迎再来,预祝生意兴隆!");

        }catch (Exception ex){
            System.err.println("出现错误:采摘量和果商数应为整数,果商数应大于零!");
            //输出完整异常信息
            ex.printStackTrace();
        }
    }
}

当输入的果商为0时,示列4的运行结果如下

请输入果实的采摘量(公斤):
3200
请输入果商数(家):
0
出现错误:采摘量和果商数应为整数,果商数应大于零!
java.lang.ArithmeticException: / by zero
    at abnormal.Test4.main(Test4.java:16)

Process finished with exit code 0

当输入数据非整数时结果如下

请输入果实的采摘量(公斤):
3200
请输入果商数(家):
八斤
出现错误:采摘量和果商数应为整数,果商数应大于零!
java.util.InputMismatchException
    at java.base/java.util.Scanner.throwFor(Scanner.java:939)
    at java.base/java.util.Scanner.next(Scanner.java:1594)
    at java.base/java.util.Scanner.nextInt(Scanner.java:2258)
    at java.base/java.util.Scanner.nextInt(Scanner.java:2212)
    at abnormal.Test4.main(Test4.java:15)

Process finished with exit code 0

从上述结果可以看出,Java异常处理机制可以自动捕获不同类型的异常,如果try语句在执行过程中遇到异常,则异常处之后的代码将不再被执行,系统会将异常信息封装成相应类型的异常对象,包含异常类型,异常查询时程序的运行状况及对该异常的详细描述。如果这个异常对象与catch语句中声明的异常类型相匹配,则会被自动捕获,Java异常处理机制把该异常对象赋值给catch关键字后的异常参数,执行catch语句块中的语句。在示列4中,通过printStackTrace()语句读取异常信息。Exception类型的常用方法如下

方法描述
Void printStackTrack()输出异常堆栈信息,堆栈信息中中包含程序运行当前类的执行流程,它将输出从方法调用处到异常抛出处的方法调用序列
String getMessage()返回异常详细信息。该信息描述异常产生的原因,是printStackTrack()方法输出信息的一部分
提示:

​ 因为使用printStackTrack()方法输出的异常详细是最完整的,所以后续会使用该方法进行异常信息输出。在其输出结果中,可以自下向上观察程序的执行轨迹,最终定位到异常发生的位置。

使用try-catch-finally语句处理异常

​ 在示列4中,try语句块执行到System.out.println("每家果商供应量" + weight / num + "公斤水果。");语句时出现异常,程序将自动跳转到catch语句块中处理异常,后续输出语句将不再被执行。如果需要进行执行后面的语句System.out.println("欢迎再来,预祝生意兴隆!");则需要添加flnally语句。代码如下

示列5

package abnormal;

import java.util.Scanner;


public class Test5 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        try {
            System.out.println("请输入果实的采摘量(公斤):");
            int weight = input.nextInt();
            System.out.println("请输入果商数(家):");
            int num = input.nextInt();
            System.out.println("每家果商供应量" + weight / num + "公斤水果。");

        }catch (Exception ex){
            System.err.println("出现错误:采摘量和果商数应为整数,果商数应大于零!");
            //输出完整异常信息
            ex.printStackTrace();
        }finally {
            System.out.println("欢迎再来,预祝生意兴隆!");
        }
    }
}

​ 运行结果如下

请输入果实的采摘量(公斤):
3200
请输入果商数(家):
0
出现错误:采摘量和果商数应为整数,果商数应大于零!
java.lang.ArithmeticException: / by zero
    at abnormal.Test4.main(Test4.java:16)
欢迎再来,预祝生意兴隆!

Process finished with exit code 0

在示列5中增加了finally语句,这样可以在异常处理过程中,无论是是否出现异常,最终都会执行finally语句块中的代码。finally语句往往会在开发中进行一些资源释放操作,无论代码是否正常执行都必须完成这些操作。

​ 需要注意的是,即使在try语句块或catch语句块中添加return语句,finally语句也会被正常执行,代码如下

示列6

package abnormal;

import java.util.Scanner;

public class Test6 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        try {
            System.out.println("请输入果实的采摘量(公斤):");
            int weight = input.nextInt();
            System.out.println("请输入果商数(家):");
            int num = input.nextInt();
            System.out.println("每家果商供应量" + weight / num + "公斤水果。");
            //不会影响finally语块执行
            return;

        }catch (Exception ex){
            System.err.println("出现错误:采摘量和果商数应为整数,果商数应大于零!");
            //输出完整异常信息
            ex.printStackTrace();
            //不会影响finally语块执行
            return;
        }finally {
            System.out.println("欢迎再来,预祝生意兴隆!");
        }
    }
}

以上代码的执行结果,与上上代码块运行结果相同。

那么,是否有finally语句块不被执行的情况呢?在异常处理代码中执行System.exit(1),将退出JVM,代码如下

示列7

package abnormal;

import java.util.Scanner;

/**
 * 使用try-catch语句处理异常
 */
public class Test7 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        try {
            System.out.println("请输入果实的采摘量(公斤):");
            int weight = input.nextInt();
            System.out.println("请输入果商数(家):");
            int num = input.nextInt();
            System.out.println("每家果商供应量" + weight / num + "公斤水果。");
        } catch (Exception ex) {
            System.err.println("出现错误:采摘量和果商数应为整数,果商数应大于零!");
            //输出完整异常信息
            ex.printStackTrace();
            //finally语句块不被执行的唯一条件
            System.exit(1);
        } finally {
            System.out.println("欢迎再来,预祝生意兴隆!");
        }
    }
}

运行结果如下

请输入果实的采摘量(公斤):
3200
请输入果商数(家):
0
出现错误:采摘量和果商数应为整数,果商数应大于零!
java.lang.ArithmeticException: / by zero
    at abnormal.Test7.main(Test7.java:16)

Process finished with exit code 1

从以上可以看出,使用了System.exit(1)finally语句块就不再被执行。

多重catch语句

​ 在之前的示列中,程序出现的全部异常有统一的处理方式。但在实际开发中,有时会希望针对不同的异常类型采取不同的处理方法,这样就需要使用多重catch语句进行异常处理。如下所示

语法:

try{
    //有可能出现异常的语句
}[catch(异常类型 1 异常对象){
    //异常处理语句
}catch(异常类型 2 异常对象){
    //异常处理语句
}......]
[finally{
    //一定会运行到的语句
}]

在示列5中,可能会出现算术异常(ArithmeicException)和输入类型不匹配异常(InputMismatch-Exception),由于程序中只定义了一个catch语句块且其参数类型为Exception,是以上两种异常类型的父类,所以能够被该catch语句全部捕获,执行相同的异常处理程序,如果需要针对可能发生的异常类型采取不同的处理方式,则需要使用多个catch语句块分别捕获不同的异常类型,输出不同的提示信息。最后一个catch语句使用Exception类型作参数,因为它是所有异常类型的父类,可以处理前面的catch语句未匹配的异常。这样,当try块中出现异常时,所封装的异常对象就会从多重catch语句所提供的参数类型中找到能够匹配的一个,执行其中的异常代码,如下所示

示列8

package abnormal;

import java.util.InputMismatchException;
import java.util.Scanner;


public class Test8 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        try {
            System.out.println("请输入果实的采摘量(公斤):");
            int weight = input.nextInt();
            System.out.println("请输入果商数(家):");
            int num = input.nextInt();
            System.out.println("每家果商供应量" + weight / num + "公斤水果。");
        } catch (ArithmeticException ex) {
            System.err.println("出现错误:采摘量和果商数应为整数,果商数应大于零!");
            //输出完整异常信息
            ex.printStackTrace();
        } catch (InputMismatchException ex){
            System.err.println("出现错误:果实采摘量和果商数应为整数!");
        }catch (Exception ex){
            System.err.println("其他未知错误!");
            ex.printStackTrace();
        }finally {
            System.out.println("欢迎再来,预祝生意兴隆!");
        }
    }
}

​ 如果输入的果商数为0或小于0,则会发生ArithmeticException算术异常,被第一条catch语句捕获,运行结果如下

请输入果实的采摘量(公斤):
3200
请输入果商数(家):
0
出现错误:采摘量和果商数应为整数,果商数应大于零!
java.lang.ArithmeticException: / by zero
    at abnormal.Test8.main(Test8.java:15)
欢迎再来,预祝生意兴隆!

Process finished with exit code 0

​ 如果输入的果商数为非整数类型,则会发生InputMismatchException类型不匹配异常,被第二条catch语句捕获,运行结果如下

请输入果实的采摘量(公斤):
3200
请输入果商数(家):
八家
出现错误:果实采摘量和果商数应为整数!
欢迎再来,预祝生意兴隆!

Process finished with exit code 0
注意:
  1. try语句块中发生异常时,系统将会按照从上到下的顺序依次检测每个catch语句,当匹配到某条catch语句后,后续其他catch语句块将不再执行。
  2. Exception作为参数的catch语句必须放在最后的位置,否则所有的异常都会被捕获,后面以其子类异常作为参数的catch语句将得不到被执行的机会。

异常分类以处理流程

前面已经介绍了异常处理及对程序正常执行的重要性。为了能更好的理解异常的继承结构,必须理解异常的继承结构及处理流程。下面举例了两个异常类的继承更新。

如何打开类或接口的继承结构

选中要打开的类 Ctrl+U 快捷键打开

image-20221018223752094

功能介绍:

image-20221018224207744

ArithmeticException类的继承更新如图

image-20221018224338524

InputMismatchException类的继承如图

InputMismatchException类继承结构

通过这两个异常类可以发现,所有的异常类型都继承Java.lang.Throwable类,它有两个重要的子类,分别是Error类和Exception类,异常体系结构图如下所示

image-20221018233142363

下面分别 介绍Error类和Exception类。

  1. Error类

Java.lang.Error类包含了仅靠程序本身无法恢复的严重错误,一般与JVM相关的问题,是Java运行环境的内部错误或硬件问题,如内存资源不足,JVM错误等。应用程序不应该抛出这种类型的对象(一般由JVM抛出)。假如出现这种错误,除尽力使程序安全退出外,其他方法是无能为力的。因此在进行程序设计时,应该更关注Exception类。

  1. Exception类

Java.lang.Exception类是程序本身可以处理的异常,可分为运行时(RunTimeExcption)异常与检查(Checked)异常。

  • 运行时异常:可以在程序中避免的异常。在类异常在编译代码时不会被编译器检测出来,可以正常编译运行,但当程序进行时发现异常,会输出异常堆栈信息并中止程序运行,程序员可以根据需要使用try-catch语句捕获这类异常,如空指针异常、类型转换异常、数组越界异常等,这些异常包括Java.long.RuntimeException类及其子类,通过这些具体的异常类型,能够判断程序的问题所在。Java程序常见的运行异常如下

    image-20221019101158621

  • Checked异常:除运行时异常的异常,是由用户错误或问题引起的异常,这是程序员无法预见的。在编译时,编译器会提示这类异常需要捕获。如果不进行捕获,则会出现编译错误。常见的编译错误异常有FileNotFoundException异常、SQLException异常等。

下面通过示列9说明Checked异常,实现对文件流对象的操作。

### 示列9

package abnormal;

import java.io.File;
import java.io.FileInputStream;

public class FileNoFoundExcep {
    public static void main(String[] args){
        //创建一个文件流对象
        FileInputStream fis = null;
        File file = new File("d:\\test.txt");
        //初始化文件流对象
         fis = new FileInputStream(file);
         fis.close();


    }
}

​ 在以上代码中,调用文件d:\test.txt,在编译 器中出现未处理异常:FileNotFoundException异常和IOException异常如下所示:编译器错误提示

D:\idea源文件\JAVA\练习\src\abnormal\FileNoFoundExcep.java:12:16
java: 未报告的异常错误java.io.FileNotFoundException; 必须对其进行捕获或声明以便抛出
D:\idea源文件\JAVA\练习\src\abnormal\FileNoFoundExcep.java:13:19
java: 未报告的异常错误java.io.IOException; 必须对其进行捕获或声明以便抛出

FileNotFoundException异常和IOException异常为Checked异常,必须进行异常处理才能通过编译,对示列9的代码进行修改,如下所示

package abnormal;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileNoFoundExcep {
    public static void main(String[] args){
        //创建一个文件流对象
        FileInputStream fis = null;
        File file = new File("d:\\test.txt");
        try {
            //初始化文件流对象
            fis = new FileInputStream(file);
        }catch (FileNotFoundException e){
            e.printStackTrace();
        }finally {
            try {
                fis.close();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }
}
提示:

​ 在Java中进行异常类子类命名时都会使用XXXError或XXXExeption的形式,这样也是为了从名称上帮助开发人员进行区分。

异常处理的完整流程

  1. 生成异常对象。如果程序在运行过程中出现异常,则JVM自动根据异常的连续实例化一个与之类型匹配的异常对象,如果发生异常的语句存在于try语块中,则去匹配对应的catch语句;否则由JVM进行默认处理,输出异常信息后中断执行。
  2. 执行catch语句块。将所生成的异常对象与try后每一条catch语句卡进行比较。如果catch语句块的异常参数能够与当前产生的异常对象匹配,则执行该catch语句块进行异常处理;否则,继续向下匹配其他catch语句块。如果无匹配的catch语句块。如果无匹配的catch,则异常对象交由JVM进行默认处理,输出异常信息。
  3. 执行finally语句块。无论最终是否有匹配的catch语句块,都会执行finally语句块;如果没有finally语句块,则忽略。

​ 整个过程类似于方法传参,所生成的异常对象根据catch语句后面的参数进行匹配,依据Java面向对象向上转型的原理,所有异常对象都可以向其父类进行类型转换,所以所有的异常对象都可以所以Exception对象来接收。当

无需对异常进行细分处理时,就可以简单地实现异常处理;否则,就需要多重catch语句对异常分别处理。

声明异常 throws 关键字

根据设计,不适合立即处理异常,而继续声明异常,交由上一级处理。throws 他不会立即处理异常而会继续声明异常。

throws关键字为方法可能抛出异常的声明,用在所声明的方法时,表示该方法可能抛出此类异常

语法:
pulbic void 方法名() throws 异常类型[,异常类型]{
//方法体
}

throws可以在方法定义处声明一类或多类异常,多类异常间使用逗号分隔。

示列10:

package abnormal;

import java.util.InputMismatchException;
import java.util.Scanner;


public class Test10 {
    public static void main(String[] args) {
        try {

        } catch (Exception ex) {
            System.err.println("出现错误:采摘量和果商数应为整数,果商数应大于零!");
            //输出完整异常信息
            ex.printStackTrace();
        }finally {
            System.out.println("欢迎再来,预祝生意兴隆!");
        }
    }
    public static void calculation() throws Exception{
        Scanner input = new Scanner(System.in);
        System.out.println("请输入果实的采摘量(公斤):");
        int weight = input.nextInt();
        System.out.println("请输入果商数(家):");
        int num = input.nextInt();
        System.out.println("每家果商供应量" + weight / num + "公斤水果。");
    }
}

​ 在以上代码中,使用throws Exception声明calculation()方法可能发生的异常。也可以在throws关键字后声明多个异常。例如

    public static void calculation() throws ArithmeticException,InputMismatchException{
        Scanner input = new Scanner(System.in);
        System.out.println("请输入果实的采摘量(公斤):");
        int weight = input.nextInt();
        System.out.println("请输入果商数(家):");
        int num = input.nextInt();
        System.out.println("每家果商供应量" + weight / num + "公斤水果。");
    }

示例10中,calculation()方法声明了异常,调用者有以下两种处理方式。

  1. 通过try-catch语句处理异常
  2. 通过throws语句继续声明异常,交由上一级处理。

抛出异常 throw 关键字

有时可能会出现以下情况

  1. 需要根据程序逻辑自定义异常类,这些异常类在java中并未提供,不能抛出。
  2. 根据业务需要自行选择异常抛出时机或自定义异常处理逻辑。例如:根据不同的逻辑判断条件而抛出异常。

以上情况下,需要throw关键字自行手动抛出异常,由调用者处理抛出异常的实际和异常处理逻辑

语法如下:

throw new 异常名 ([参数列表]);
例如:
throw new Exception();
注意:
用throw关键字抛出的只能为Throwable类或其子类的对象,
错误示例:
throw new String("exception");

​ 使用throw关键字可以根据程序业务逻辑,自行抛出异常,如下所示

示列11

package abnormal;

import java.util.InputMismatchException;
import java.util.Scanner;


public class Test11 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.err.println("请输入你的年龄:");
        int age = input.nextInt();
        try {
            Test11 test11 = new Test11();
            System.err.println(test11.ShowTicketPrice(age));
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }
    /**
     * 根据年龄显示票价信息
     */
    public String ShowTicketPrice(int age) throws  Exception{
        if (age<3){
            throw  new Exception("你录入的年龄有误,3岁以下儿童暂不能观影");
        }else if (age >= 60||age <=6){
            return "你可以购买半价票25元";
        }else {
            return "你需要购买全价票50元";
        }
    }
}

​ 当录入年龄错误时

请输入你的年龄:1
java.lang.Exception: 你录入的年龄有误,3岁以下儿童暂不能观影
    at abnormal.Test11.ShowTicketPrice(Test11.java:24)
    at abnormal.Test11.main(Test11.java:14)

Process finished with exit code 0

​ 当录入年龄成功时

请输入你的年龄:
6
你可以购买半价票25元

Process finished with exit code 0

自定义异常

当java异常体系提供的异常类型不能满足程序的需要时,可以自定义类

步骤

  1. 定义异常类,继承Exception类或RuntimeException类。
  2. 编写异常类的构造方法,并继承父类的实现。常见的构造方法有四种,可根据需求选择添加实现。构造方法如下所示

    //构造方法 1
    public Exception(){
        super();
    }
    //构造方法2
    public Exception(String message){
        super();
    }
    //构造方法3
    public Exception(String message,Throwable cause){
        super(message,cause);
    }
    //构造方法4
    public Exception(Throwable cause){
        super(cause);
    }
  3. 实例化自定义异常对象,并使用throw关键字抛出 ,使用自定义异常实现示列12
package abnormal;

import java.util.InputMismatchException;
import java.util.Scanner;


public class Test11 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.println("请输入你的年龄:");
        int age = input.nextInt();
        try {
            Test11 test11 = new Test11();
            System.out.println(test11.ShowTicketPrice(age));
        } catch (AgeException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 根据年龄显示票价信息
     */
    public String ShowTicketPrice(int age) throws AgeException {
        if (age < 3) {
            throw new AgeException("你录入的年龄有误,3岁以下儿童暂不能观影");
        } else if (age >= 60 || age <= 6) {
            return "你可以购买半价票25元";
        } else {
            return "你需要购买全价票50元";
        }
    }
    /**
    *年龄异常
    */
    public class AgeException extends Exception {
        public AgeException() {

        }

        public AgeException(String message) {
            super(message);
        }

        public AgeException(String message, Throwable cause) {
            super(message, cause);
        }

        public AgeException(Throwable cause){
            super(cause);
        }
    }

}

经验:

使用throw关键字可以抛出自定义异常,那么自定义异常有哪些应用场景?

  1. 项目开发一般由团队成员共同完成,为了统一对外的异常展示方式,可以使用自定义异常。
  2. 项目中因业务逻辑错误需要抛出异常,但一般是符合Java语法的,所以在Java中不会存在这类异常,例如:年龄异常、性别异常等等。
  3. 使用自定义异常可以隐藏底层异常,精准定位,异常信息更直观。自定义异常可以抛出明确的异常信息,根据异常名也可以区分其发生的位置,分别进行程序的修改
最后修改:2022 年 10 月 19 日
如果觉得我的文章对你有用,请随意赞赏