详解Java中的异常体系机构(throw,throws,try catch,finally)


目录

一.异常的概念

二.异常的体系结构

三.异常的处理

异常处理思路

LBYL:Look Before You Leap

EAFP: It's Easier to Ask Forgiveness than Permission

异常抛出throw

异常的捕获

提醒声明throws

 try-catch捕获处理

finally的作用

四.自定义异常类


一.异常的概念

有一句话说的很好 ”程序员不是在写BUG就是在改BUG” ,在日常开发中,程序员绞尽脑汁的去写出完美的代码,但是在程序运行过程中难免回遇见一些奇奇怪怪的问题。而这些问题与BUG总是很难去控制,用人类的思维去看明明是很完美的一个逻辑处理,但是交给编译器就产生的结果总会与我们的预期大相径庭,在Java中,我们将程序执行过程中发生的不正常的行为称为异常,比如什么算数异常啊,数组越界异常啊,空指针异常啊这都属于异常的范围,我们统称为异常

        System.out.println(10 / 0);
        // 执行结果Exception in thread "main" java.lang.ArithmeticException
        
        int[] arr1 = {1, 2, 3};
        System.out.println(arr1[100]);
        // 执行结果Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
        
        int[] arr2 = null;
        System.out.println(arr2.length);
        // 执行结果Exception in thread "main" java.lang.NullPointerException

并且我们可以看见在Java中对于不同的异常,都有对应的类来描述


二.异常的体系结构

实际上异常的种类是很多的,为了应对不同的异常或者错误,Java提供了一个非常庞大的异常体系机构供程序员来更好的维护代码的安全性,如下图所示

异常可能发生在编译阶段,可能发生在运行阶段,因此我们可以按照异常发生的时间段将其进行分类:

  • 编译时异常,也叫做受查异常
  • 运行时异常,也叫做非受查异常 

但是诸如将单词拼写错误导致的问题我们程序出现问题的情况不属于异常


三.异常的处理

代码中存在异常并不是什么奇怪的事情,但是在出现异常后,我们需要及时通知程序员去修改,对于异常的处理,我们分为俩种思路

异常处理思路

LBYL:Look Before You Leap

也就是说我们在操作之前就对异常做出充分的检查,也就是事先防御型,比如我们在设计一款游戏的时候,我们就需要对其中可能发生的每一个错误做出处理机制和避免机制

        boolean ret = false;
        ret = loginGame();
        if (!ret) {
            //处理登陆游戏错误;
            return;
        }
        ret = startMatch();
        if (!ret) {
            //处理匹配错误;
            return;
        }
        ret = conGame();
        if (!ret) {
            //处理游戏确认错误;
            return;
        }
        ret = choiceChar();
        if (!ret) {
            //处理选择英雄错误;
            return;
        }
        ret = loading();
        if (!ret) {
            //处理载入游戏错误;
            return;
        }

但这样的处理会有一个缺陷:正常流程和错误处理流程代码混在一起, 代码整体显的比较混乱

EAFP: It's Easier to Ask Forgiveness than Permission

这样的思想主要解决的问题不是如何提前避免异常,而是在异常出现以后如何进行合理的应对

        try {
            loginGame();
            startMatch();
            conGame();
            choiceChar();
            loading();

        } catch (loginGame异常) {
            //处理登陆游戏错误;
        } catch (startMatch异常) {
            //处理匹配错误;
        } catch (conGame异常) {
            //处理游戏确认错误;
        } catch (choiceChar异常) {
            //处理选择英雄错误;
        } catch (loading异常) {
            //处理载入游戏错误;
        }

在Java中对于异常处理的核心机制就是EAFP,Java中常用的有5个异常处理的关键字

  • throw
  • try
  • catch
  • final
  • throws

异常抛出throw

在Java中,可以借助throw关键字,抛出一个指定的异常对象,将错误信息告知给调用者。具体语法如下:

throw new XXXException ("异常产生的原因");

示例: 

    public static int getElement(int[] array, int index){
        if(null == array){
            throw new NullPointerException("传递的数组为null");
        }
        if(index < 0 || index >= array.length){
            throw new ArrayIndexOutOfBoundsException("传递的数组下标越界");
        }
        return array[index];
    }
    public static void main(String[] args) {
        int[] array = {1, 2, 3};
        getElement(array, 3);
    }

 注意:

  1. throw必须写在方法体内部
  2. 抛出的对象必须是Exception 或者 Exception 的子类对象
  3. 如果抛出的是 RunTimeException 或者 RunTimeException的子类,则可以不用处理,直接交给JVM来处理
  4. 如果抛出的是编译时异常,用户必须处理,否则无法通过编译
  5. 异常一旦抛出,其后的代码就不会执行

异常的捕获

异常的捕获就是指我们对异常的处理,通常我们有俩种方式去处理:

  • 异常声明throws
  • try-catch捕获处理

提醒声明throws

处在方法声明时参数列表之后,当方法中抛出编译时异常,用户不想处理该异常,此时就可以借助throws将异常抛给方法的调用者来处理。也就是说当前方法不处理异常提醒方法的调用者处理异常

语法格式:

修饰符 返回值类型 方法名 (参数列表) throws 异常类型1,异常类型2...{

}

public class Config {
    File file;
    /*
    FileNotFoundException : 编译时异常,表明文件不存在
    此处不处理,也没有能力处理,应该将错误信息报告给调用者,让调用者检查文件名字是否给错误了
    */
    public void OpenConfig(String filename) throws FileNotFoundException {
        if (filename.equals("config.ini")) {
            throw new FileNotFoundException("配置文件名字不对");
        }
        // 打开文件
    }
}

注意事项:

  • throws必须跟在方法参数列表之后
  • 抛出的问题必须是Exception 或者 Exception的子类对象
  • 方法内部如果抛出了多个异常,throws之后必须跟多个异常类型,之间用逗号隔开,如果抛出多个异常类型具有父子关系,直接声明父类即可
  • 调用声明抛出的异常方法时,调用者必须对异常做出处理,或者继续使用throws抛出

示例: 

class Config {
    File file;
    // FileNotFoundException 继承自 IOException
    public void OpenConfig(String filename) throws IOException {
        if(filename.endsWith(".ini")){
            throw new IOException("文件不是.ini文件");
        }
        if(filename.equals("config.ini")){
            throw new FileNotFoundException("配置文件名字不对");
        }
        // 打开文件
    }
    public void readConfig(){
    }
    public void openConfig(String s) {
    }
    public static void main(String[] args) throws IOException {
        Config config = new Config();
        config.openConfig("config.ini");
    }
}

 try-catch捕获处理

刚才我们提到的throws并没有对异常做出处理,他只是将异常报给调用者,让调用者去处理,而如果要对异常真正的处理就需要使用try-catch

try-catch的一般使用语法如下,其中catch:可以有一个也可以有多个,根据具体需求分配,finally可以有也可以没有,但是如果有的话finally中的代码就一定会执行,并且try中的代码也可以不出现异常:

try{
    // 将可能出现异常的代码放在这里
    }catch(要捕获的异常类型 e){
        // 如果try中的代码抛出异常了,此处catch捕获时异常类型与try中抛出的异常类型一致时
        //或者是try中抛出异常的基类时,就会被捕获到
        //对异常就可以正常处理,处理完成后,跳出try-catch结构,继续执行后序代码
    }catch(异常类型 e){
        // 对异常进行处理
    }finally{
        // 此处代码一定会被执行到
    }
}

示例:

class Config {
    File file;
    public void openConfig(String filename) throws FileNotFoundException{
        if(!filename.equals("config.ini")){
            throw new FileNotFoundException("配置文件名字不对");
        }
        // 打开文件
    }
    public void readConfig(){
    }
    public static void main(String[] args) {
        Config config = new Config();
        try {
            config.openConfig("config.txt");
            System.out.println("文件打开成功");
        } catch (IOException e) {
        // 异常的处理方式
        //System.out.println(e.getMessage()); // 只打印异常信息
        //System.out.println(e); // 打印异常类型:异常信息
            e.printStackTrace(); // 打印信息最全面
        }
        // 一旦异常被捕获处理了,此处的代码会执行
        System.out.println("异常如果被处理了,这里的代码也可以执行");
    }
}

注意:

  •  try块内抛出异常位置之后的代码将不会被执行
  •  如果抛出异常类型与catch时异常类型不匹配,即异常不会被成功捕获,也就不会被处理,继续往外抛,直到JVM收到后中断程序----异常是按照类型来捕获的
  •  try中可能会抛出多个不同的异常对象,则必须用多个catch来捕获----即多种异常,多次捕获
  • 如果异常之间具有父子关系,一定是子类异常在前catch,父类异常在后catch,否则语法错误

finally的作用

在写程序时,有些特定的代码,不论程序是否发生异常,都需要执行,比如程序中打开的资源:网络连接、数据库连接、IO流等,在程序正常或者异常退出时,必须要对资源进进行回收。另外,因为异常会引发程序的跳转,可能导致有些语句执行不到,finally就是用来解决这个问题的。

关于异常的处理方式,异常的种类有很多,我们要根据不同的业务场景来决定

  • 对于比较严重的问题(例如和算钱相关的场景), 应该让程序直接崩溃, 防止造成更严重的后果
  • 对于不太严重的问题(大多数场景), 可以记录错误日志, 并通过监控报警程序及时通知程序猿
  • 对于可能会恢复的问题(和网络相关的场景), 可以尝试进行重试
  • 在我们当前的代码中采取的是经过简化的第二种方式. 我们记录的错误日志是出现异常的方法调用信息, 能很快速的让我们找到出现异常的位置. 以后在实际工作中我们会采取更完备的方式来记录异常信息

四.自定义异常类

Java中虽然已经内置了丰富的异常类, 但是并不能完全表示实际开发中所遇到的一些异常,此时就需要维护符合我们实际情况的异常结构,自定义异常通常会继承自 ExceptionRunTimeException

  • 继承自 Exception 的异常默认是受查异常
  • 继承自 RunTimeException 的异常默认是非受查异常

具体方式:

  1. 自定义异常类,然后继承自Exception 或者 RunTimeException
  2. 实现一个带有String类型参数的构造方法,参数含义:出现异常的原因

例如我们实现一个用户登陆功能: 

class UserNameException extends Exception {
    public UserNameException(String message) {
        super(message);
    }
}
class PasswordException extends Exception {
    public PasswordException(String message) {
        super(message);
    }
}
class LogIn {
    private String userName = "admin";
    private String password = "123456";
    public static void loginInfo(String userName, String password)
            throws UserNameException,PasswordException{
        if (!userName.equals(userName)) {
            throw new UserNameException("用户名错误!");
        }
        if (!password.equals(password)) {
            throw new PasswordException("用户名错误!");
        }
        System.out.println("登陆成功");
    }
    public static void main(String[] args) {
        try {
            loginInfo("admin", "123456");
        } catch (UserNameException e) {
            e.printStackTrace();
        } catch (PasswordException e) {
            e.printStackTrace();
        }
    }
}



 本次的分享就到此为止了,希望我的分享能给您带来帮助,也欢迎大家三连支持,你们的点赞就是博主更新最大的动力!如有不同意见,欢迎评论区积极讨论交流,让我们一起学习进步!有相关问题也可以私信博主,评论区和私信都会认真查看的,我们下次再见

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/184566.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

累计定点160+车型,商汤绝影凭什么领跑规模化量产?

2023广州车展火热进行&#xff0c;智能化技术加速“内卷”。 商汤绝影多款合作量产车型亮相2023广州车展&#xff0c;包括昊铂 GT、传祺ES9、E8系列和本田雅阁、捷途旅行者、极氪X等&#xff0c;全方位呈现在智能驾驶和智能座舱领域的最新成果&#xff0c;以AI“新科技”&…

RTL8762x芯片避坑总结之1——用GPIO模拟I2C

1. 使用GPIO模拟I2C&#xff1a; 1.1 按常规逻辑 在输出第1个数据&#xff0c;切换为输入读取ACK后&#xff0c;切回输出无效&#xff0c;不能输出数据&#xff1a; 1.2 在切换输入输出前&#xff0c;需要对Pad重新进行配置 重新配置后&#xff0c;输入输出切换成功&#xf…

Android开发从0开始(服务)

Android后台运行的解决方案&#xff0c;不需要交互&#xff0c;长期运行。 服务基础框架&#xff1a; public class MyService extends Service { public MyService() { } Override public IBinder onBind(Intent intent) { //activity与service交互&#xff08;需要继…

多actor实体组合并统一应用变换_vtkAssembly

开发环境&#xff1a; Windows 11 家庭中文版Microsoft Visual Studio Community 2019VTK-9.3.0.rc0vtk-example参考代码 demo解决问题&#xff1a;创建了一个球体和立方体的三维可视化&#xff0c;将它们组合成一个装配体&#xff0c;应用变换&#xff0c;调整不透明度&#…

美国汽车零部件巨头 AutoZone 遭遇网络攻击

Security Affairs 网站披露&#xff0c;美国汽车配件零售商巨头 AutoZone 称其成为了 Clop MOVEit 文件传输网络攻击的受害者&#xff0c;导致大量数据泄露。 AutoZone 是美国最大的汽车零配件售后市场经销商之一&#xff0c;在美国、墨西哥、波多黎各、巴西和美属维尔京群岛经…

opencv-Meanshift 和 Camshift 算法

MeanShift 和 CamShift 都是用于目标跟踪的算法&#xff0c;基于颜色直方图的方法。它们主要用于在视频序列中追踪运动的对象。 MeanShift&#xff08;均值漂移&#xff09;: 原理: MeanShift 算法的基本思想是通过不断调整窗口的中心&#xff0c;使得窗口中的样本点的平均值向…

【前端】让列表像Excel单元格一样编辑

前言 领导说了一堆的话,最后总结一句就是客户很懒,客户的员工更加懒。 本着让别人节省时间的原则,提倡出了让列表和Excal的单元格一样,不仅看数据还可以随时更改数据。 查资料 根据 Jeecg-Vue3 源码介绍,从而知道是基于 Vben Admin 开源项目进行改造的。 因此在 Vben…

JavaScript之DOM操作

第一章 API介绍 ​API是一种事先定义好的函数&#xff0c;用来提供应用程序与开发人员基于某软件或硬件得以访问的一组例程&#xff0c;而又无需访问源码&#xff0c;或理解内部工作机制的细节。 ​Web API接口&#xff1a;浏览器提供的一系列操作浏览器功能和页面元素的API(BO…

opencv-背景减除

背景减除&#xff08;Background Subtraction&#xff09;是一种用于从视频序列中提取前景对象的计算机视觉技术。该技术的主要思想是通过建模和维护场景的背景&#xff0c;从而检测出在不同时间点出现的前景对象。 OpenCV 提供了一些用于背景减除的函数&#xff0c;其中最常用…

记录ruoyi-plus-vue部署的问题

ruoyi-vue-plus5.x 后端 ruoyi-vue-plus5.x 前端 前端本地启动命令 # 克隆项目 git clone https://gitee.com/JavaLionLi/plus-ui.git# 安装依赖 npm install --registryhttps://registry.npmmirror.com# 启动服务 npm run dev# 构建生产环境 yarn build:prod # 前端访问地址…

深入学习pytorch笔记

两个重要的函数 dir()&#xff1a; 一个内置函数&#xff0c;用于列出对象的所有属性和方法 help()&#xff1a;一个内置函数&#xff0c;用于获取关于Python对象、模块、函数、类等的详细信息 Dateset类 Dataset&#xff1a;pytorch中的一个类&#xff0c;开发者在训练和…

什么是高防CDN?CDN的设计原理及应用场景是什么?

随着互联网的快速发展&#xff0c;人们对网络的速度和稳定性要求也越来越高。CDN技术作为网络优化的重要手段&#xff0c;被越来越多的企业和网站所采用。现在我为大家介绍一下CDN的设计原理以及应用场景。 一.高防CDN技术概述 高防CDN是一种应用了高级防御技术的内容分发网络…

【大数据】Docker部署HMS(Hive Metastore Service)并使用Trino访问Minio

本文参考链接置顶&#xff1a; Presto使用Docker独立运行Hive Standalone Metastore管理MinIO&#xff08;S3&#xff09;_hive minio_BigDataToAI的博客-CSDN博客 一. 背景 团队要升级大数据架构&#xff0c;需要摒弃hadoop&#xff0c;底层使用Minio做存储&#xff0c;应用…

配置mvn打包参数,不同环境使用不同的配置文件

方法一&#xff1a; 首先在/resource目录下创建各自环境的配置 要在不同的环境中使用不同的配置文件进行Maven打包&#xff0c;可以使用Maven的profiles特性和资源过滤功能。下面是配置Maven打包参数的步骤&#xff1a; 在项目的pom.xml文件中&#xff0c;添加profiles配置…

Lubuntu 23.10用户可使用LXQt 1.4桌面

导读在众多 Lubuntu 用户的要求下&#xff0c;Lubuntu 开发人员决定将 LXQt 1.4 桌面环境向后移植到最新的 Lubuntu 23.10 &#xff08;Mantic Minotaur&#xff09; 版本。 是的&#xff0c;您没看错&#xff0c;您现在可以使用官方的 Lubuntu Backports PPA&#xff08;个人软…

“java.lang.IllegalStateException: No ConfigurableListableBeanFactory set“,缺少配置

一、错误分析 做品优购项目的运营商安全登录时&#xff0c;运行项目后&#xff0c;浏览器访问模板页&#xff0c;模板页的表格无法正常显示&#xff0c;报错信息如下&#xff1a; SEVERE: StandardWrapper.Throwable java.lang.IllegalStateException: No ConfigurableLista…

window.requestAnimationFrame+localStorage+canvas实现跨窗口小球连线效果

文章目录 前言效果代码后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;前端系列文章 &#x1f431;‍&#x1f453;博主在前端领域还有很多知识和技术需要掌握&#xff0c;正在不断努力填补技术短板。(如果出现错误&#xff0c;感谢大家…

session、cookie的区别

前言 cookie存在于客户端&#xff08;浏览器&#xff09;&#xff0c;session存在于服务端。session的主要信息存在于服务器&#xff0c;在客户端只存放一个sessionid&#xff08;基于cookie的&#xff09;&#xff0c;每次请求&#xff0c;客户端都会自动把sessionid发送到服…

儿童在线学习系统 宝宝云幼儿园服务微信小程序的设计与实现

综合运用所学的程序设计基础、数据结构、数据库原理及应用、高级语言程序设计、面向对象程序设计、软件需求分析与建模、软件设计与体系结构、软件测试等课程知识&#xff0c;设计开发一个较实用的应用系统。 通过该设计可以巩固并提高软件工程专业学生的软件需求分析、设计、开…

css实现图片绕中心旋转,鼠标悬浮按钮炫酷展示

vue模板中代码 <div class"contentBox clearfix home"><div class"circle"><img class"in-circle" src"../../assets/img/in-circle.png" alt""><img class"out-circle" src"../../as…