[Java]异常及其处理

画师:竹取工坊

大佬们好!我是Mem0rin!现在正在准备自学转码。

如果我的文章对你有帮助的话,欢迎关注我的主页Mem0rin,欢迎互三,一起进步!


文章目录


一、 异常的体系结构

异常指的是程序中的不正确行为,比如之前遇到的数组越界,空指针异常等。

通常说的异常是Java中的 Exception ,与之并列的是 Error ,指的是JVM无法处理的严重问题,比如JVM内部问题、资源耗尽等,代表是 StackOverflowError 和 OutOfMemoryError。

ExceptionError 都是异常体系的顶层类 Throwable 的子类,Exception 又分为编译时异常(受查异常)和运行时异常(非受查异常),受查异常强制要求编译器进行处理,否则无法编译。

再往下分类出更加具体的各种异常,比如上面提到的数组越界异常。

详见下图:

二、异常的处理

throw 关键词

throw 用于人为抛出异常,例如:

java 复制代码
throw new ArrayIndexOutOfBoundsException("人为抛出数组越界异常");

得到的结果为:

复制代码
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 人为抛出数组越界异常
	at TestDemo.main(TestDemo.java:11)

throws 关键词

throws 关键词用于声明该方法可能会产生异常,需要进行处理,相当于是把处理异常的部分交给了方法的调用者。

throws 关键词在定义方法的时候使用,如果需要声明多个异常则用逗号隔开,比如以下实例:

java 复制代码
public static void ExceptionProducer() throws ArithmeticException, AbstractMethodError {
    throw new ArithmeticException("1111");
}

try-catch-finally

产生异常,抛出异常,现在终于到了处理异常的环节了。

trycatchfinal分别对应着处理异常的"运行"、"处理"和"收尾"三个阶段。

例如以下实例:

java 复制代码
try {
    System.out.println("抛出异常");
    throw new ArrayIndexOutOfBoundsException("人为异常");
} catch(ArrayIndexOutOfBoundsException e) {
    System.out.println("已处理数组越界异常");
} finally {
    System.out.println("after");
}

结果为:

复制代码
抛出异常
已处理数组越界异常
after

接下来我们一个一个来讲:

try

try 用于运行可能会出现异常的代码,并且将产生的异常抛出。

需要注意的是,try 内部运行的代码只会到产生异常的部分,如果已经产生了异常,那后面的代码都不会运行,比如以下实例:

java 复制代码
try {
    System.out.println("抛出异常");
    throw new ArrayIndexOutOfBoundsException("人为异常");
    System.out.println("111");
} catch(ArrayIndexOutOfBoundsException e) {
    System.out.println("已处理数组越界异常");
} finally {
    System.out.println("after");
}

编译器会警告说 System.out.println("111"); 是无法执行的语句。

这对于 throw 关键词也是一样的,在下面的实例中也会被警告说这是无法执行的语句

java 复制代码
throw new ArrayIndexOutOfBoundsException("人为抛出数组越界异常");
throw new ArithmeticException("111");
catch

catch 用于捕获 try 产生的异常,形式是 catch(异常类型 e) {语句},如果 catch 中的异常类型和抛出的异常类型一样,则会捕获异常类型并运行对应语句。

异常的捕获存在父子类的关系,也就是说抛出的子类的异常可以被父类的 catch 捕获。同时因为一个异常只会被一个 catch 语句捕获,因此如果在捕获父类异常的时候想要单独捕获子类的异常的时候,需要把子类的异常写在前面,就像以下示例:

java 复制代码
try {
    System.out.println("抛出异常");
    throw new ArrayIndexOutOfBoundsException("人为异常");
} catch(ArrayIndexOutOfBoundsException e) {
    System.out.println("已处理数组越界异常");
} catch(Exception e) {
    System.out.println("111");
} finally {
    System.out.println("after");
}

如果中间两个 catch 写反了就会显示:已捕获到异常错误java.lang.ArrayIndexOutOfBoundsException。

如果 try 运行在不同的情形下可能会产生了多个异常,可以用多个 catch 进行捕获,并进行处理,例如以下实例:

java 复制代码
int[] array = {1};
try {
    //array = null;
    int a = array[110];
} catch(ArrayIndexOutOfBoundsException e) {
    System.out.println("已处理数组越界异常");
} catch(NullPointerException e) {
    System.out.println("已处理空指针异常");
} finally {
    System.out.println("after");
}

现在抛出的结果是数组越界异常,如果去掉注释就是空指针异常。

如果这两个异常的处理方式相同,还可以采取并列的方式:

java 复制代码
int[] array = {1};
try {
    array = null;
    int a = array[110];
} catch(ArrayIndexOutOfBoundsException | NullPointerException e) {
    System.out.println("已处理异常");
} finally {
    System.out.println("after");
}
finally

用于处理异常的收尾阶段,具有必然运行 的特点,可以用于运行无论程序是否发生异常都需要执行的代码,比如回收资源。

java 复制代码
public static int getData(){
        Scanner sc = null;
        try{
            sc = new Scanner(System.in);
            int data = sc.nextInt();
            return data;
        }catch (InputMismatchException e){
            e.printStackTrace();
        }finally {
            System.out.println("finally中代码");
        }
        System.out.println("try-catch-finally之后代码");
        if(null != sc){
            sc.close();
        }

        return 0;
    }
    public static void main(String[] args) {
        int data = getData();
        System.out.println(data);
    }

(懒得调缩进了将就着看一下()

我们会发现finally中代码和try-catch-finally后的代码是有运行的差别的,finally之后的代码可能无法执行,如果资源回收在try-catch-finally后执行的话可能会被跳过。

因此finally的存在是有必要的。

三、自定义异常

在实际使用中,现有的异常可能不完全符合我们的需求,这个时候我们就可以自定义一个异常类型。实例如下:

java 复制代码
public class NameException extends Exception{
    public NameException(String message) {
        super(message);
    }
}

想要抛出该异常可以:

java 复制代码
if (name != userName) {
    throw new NameException("用户名错误");
}

继承自 Exception 的异常默认为受查异常。

继承自 RunException 的异常默认为运行时异常。

相关推荐
杰克尼1 分钟前
知识点总结--02(java基础部分)
java·开发语言·jvm
Sunshine for you2 分钟前
C++中的对象池模式
开发语言·c++·算法
暮冬-  Gentle°15 分钟前
编译器优化屏障使用
开发语言·c++·算法
华科大胡子20 分钟前
此电脑网络位置异常的AD域排错指南
开发语言·php
m0_7301151126 分钟前
模板编程中的SFINAE技巧
开发语言·c++·算法
mldlds28 分钟前
Spring Boot 实战:轻松实现文件上传与下载功能
java·数据库·spring boot
xxjj998a33 分钟前
Spring Boot 整合 Apollo 配置中心实战
java·spring boot·后端
2401_8318249636 分钟前
高性能计算集群部署
开发语言·c++·算法
武超杰1 小时前
Spring 纯注解配置全解析(进阶版)
java·开发语言
机器视觉知识推荐、就业指导1 小时前
LVGL真能动摇Qt的地位吗?
开发语言·qt·系统架构