Java体系中的异常

在这里插入图片描述

1. 异常


1.1 异常的概念

在Java中,我们将程序执行过程中发生的不正常行为称为异常。异常是在程序运行过程中发生的错误或意外情况,它打破了程序的正常执行流程。在Java中通过面向对象的编程思想,我们也将这些扰乱程序正常执行的行为用类组织起来,也就是说异常实际上是由一个一个的类所组成

  1. IndexOutOfBoundsException下标越界异常
  2. ArithmeticException算术异常
  3. NullPointerException空指针异常
  4. ClassCastException类型转换异常
  5. StackOverFlowError栈溢出错误
  6. .....

从上述列举过程看来,Java中对于不同类型的异常,我们都有与之对应的类来进行描述,也就是说异常拥有一套体系结构。

1.2 异常的体系

异常的种类很多,为了对不同的异常/错误等进行分类管理,Java内部维护了一个异常的体系结构:
在这里插入图片描述

Throwable:异常体系的顶层类,其派生出两个子类:ErrorException.
Error: 对于Java虚拟机无法解决的严重问题,如JVM的内部错误、资源耗尽,如StackOverFlowErrorOutOfMemoryError等,我们会抛出一个错误
Exception: 异常产生后可由人为通过代码处理,使得程序能够继续执行,就是我们常说的异常Exception.

我们常说的异常Exception可以分为编译时异常和运行时异常。

  1. 编译时异常:
    在程序编译期间发生的异常,称为编译时异常,也可以称为受查异常(Checked Exception),除了RuntimeException及其子类之外的其他在Exception下的异常包括Exception我们都称之为受查异常。
  2. 运行时异常:
    在程序执行期间发生的异常,称为运行时异常,也可以称为非受查异常(Unchecked Exception),RuntimeException以及其子类对应的异常,我们都称之为运行时异常。

Exception的注意事项:

  1. 编译时异常是在编译时期抛出的,会在编译期间检查程序是否会出现问题,一但出现编译时异常,强制要求我们进行处理,否则无法进行编译。
  2. 运行时异常是在Java虚拟机正常运行期间抛出的异常,这些异常在编译时不强制要求处理。
  3. 编译时出现的语法性错误,不能称之为异常;例如:在拼写System.out.println();时,将大小写拼写错误写成system.out.println(),此时不需要异常出现的情况。

1.3 自定义异常类

Java 中虽然已经内置了丰富的异常类, 但是并不能完全表示实际开发中所遇到的一些异常,此时就需要定义我们实际情况下所需要的异常结构。

//如何根据需求自定义一个异常类呢?
//(1)自定义异常类,必须继承自Exception 或者 RuntimeException
//(2)实现一个带String类型参数的构造方法,参数意义:书写出现异常的原因//例如:实现一个用户登录时用户名或密码错误时的登录异常//LogInException.java  --自定义的登录异常类
public class LogInException extends RuntimeException {public LogInException(String message) {  super(message);  }public LogInException() {  super();  }
}//--使用//Login.java
public class LogIn {//账号、密码private String userName = "admin";private String password = "123456";public static void loginInfo(String userName, String password) throws LogInException {if((!this.userName.equals(userName) || (!this.password.equals(password)) {throw new LogInException("用户名和密码不匹配");}System.out.println("登陆成功");}}	//Main.java
public class Main {public static void main(String[] args) {LogIn logIn = new LogIn();try {logIn.loginInfo("admin","123456");}catch(LogInException e) {e.printStackTrace();}finally {System.out.println("finally中的代码一定会执行,且在try-catch-finally中最有执行。");}}
}

根据上面代码的处理结果,我们知道:

  • 自定义异常通常会继承自Exception 或RuntimeException。
  • 继承自 Exception 的异常默认是受查异常
  • 继承自 RuntimeException的异常默认是非受查异常

2. 异常的处理


在异常处理中,我们需要用到的5个主要关键字是:throwtrycatchfinallythrows

2.1 异常的抛出

在编写程序时,如果程序中出现错误,我们想将错误信息告知调用者,如:参数检查错误等,我们可以借由异常实现。在Java中,可以借助throw关键字抛出一个指定的异常对象(常抛出自定义的异常),将出现的问题借由错误信息告知调用者

//语法规则如下:
throw new 'XXX'Exception("异常产生的原因");

实例:实现一个获取数组中任意位置元素的方法

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];
}

[注意事项]

  1. 抛出的对象必须时Exception或Exception的子类对象,也就是说抛出的异常必须继承Exception或继承自Exception的子类。
  2. 如果抛出的是运行时异常RuntimeException或其子类,则可直接交由JVM进行处理
  3. 如果抛出的是编译时异常,用户必须处理,否则无法通过编译
  4. 异常抛出后,其后的代码就不会执行了

2.2 异常的处理

异常的处理主要有两种:异常声明throws以及try-catch-finally捕获处理

2.2.1 异常声明throws

当方法中抛出编译时异常,用户不想处理该异常,此时可以借由throws声明异常,将异常抛给方法的调用者来处理。即当前方法不处理异常,提醒方法的调用者处理异常。

//语法格式:异常声明处在方法声明时参数列表之后
修饰符 返回值类型 方法名(参数列表)throws 异常类型1,异常类型2... {...
}

示例:

public static void loginInfo(String userName, String password) throws LogInException {if((!this.userName.equals(userName) || (!this.password.equals(password)) {throw new LogInException("用户名和密码不匹配");}System.out.println("登陆成功");}

我们在当前的loginInfo方法中并没有处理LogInException,而是通过异常的声明将可能出现的异常报告给调用者,让调用者来解决处理这个问题。当调用者也不想处理这个问题,可以在调用的方法中也声明这个异常交给下一个调用这个调用的方法的人解决。

//也就是说如果在main方法中没有用try-catch-finally捕获的话,可以声明异常
public class Main {public static void main(String[] args) throws LogInException {LogIn logIn = new LogIn();/*try {logIn.loginInfo("admin","123456");}catch(LogInException e) {e.printStackTrace();}finally {System.out.println("finally中的代码一定会执行,且在try-catch-finally中最有执行。");}*/logIn.loginInfo("admin","123456");}
}

对于异常声明,我们需要注意一下几个问题:

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

2.2.2 try-catch-finally捕获并处理

throws对异常并没有真正处理,而是将异常报告给抛出异常方法的调用者,由调用者处理。如果真正要对异常进行处理,就需要try-catch-finally
Tip: [中括号中的内容可加可不加],中括号内的内容表示可选;即可加也可不加

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

也就是说try-catch-finally捕获中可能存在多个异常,这也就说我们可以拥有多个catch来捕获异常。上面对用户登录的例子中展现了try-catch-finally对异常的捕获。
我们以一段代码作为切入点来理解我们说到的try-catch-finally捕获:

public static void main(String[] args) {int[] arr = {1, 2, 3};try {System.out.println("try代码块中执行前");//arr = null;//(1)//arr = new int[101];//(2)System.out.println(arr[100]);System.out.println("try代码块中执行后");}catch (ArrayIndexOutOfBoundsException e) {System.out.println("这是个数组下标越界异常");e.printStackTrace();}catch (NullPointerException e) {System.out.println("这是个空指针异常");e.printStackTrace();}finally {System.out.println("finally中的代码一定会执行");}System.out.println("after try-catch-finally");}
  1. 不放开注释内容(1)和(2)的运行结果:
    在这里插入图片描述

我们发现在try快中抛出异常位置后的代码将不会被执行,异常抛出后如果能被catch语句捕捉到则执行catch语句中的内容,然后执行finally快中的内容,当抛出异常并捕获到异常后,后序代码能够继续执行。
2. 当我们放开注释内容(1)后,执行代码,运行结果如下:
在这里插入图片描述

通过运行结果我们能够发现这次出现的是空指针异常,也就是说这次我们的异常被第二个catch语句捕获到了。这说明我们try快中的内容可以存在多个可能出现的异常,但是我们只能够捕获一个异常,也就是说我们不会同时抛出多个异常。
3. 当我们放开注释内容(2)后,执行代码,运行结果如下:
在这里插入图片描述

运行结果说明无论有没有抛出异常,一但存在finally快,我们都会执行finally块中的内容。
前面我们说过try-catch-finally捕获中[中括号]的内容可以不存在,也就是说finally快可以不存在,当finally快存在时,finally中的代码一定会执行。

// 下面程序输出什么?
public static void main(String[] args) {System.out.println(func());
}
public static int func() {try {return 10;} finally {return 20;}
}//A: 10   B: 20   C: 30   D: 编译失败

finally 执行的时机是在方法返回之前(try 或者 catch 中如果有 return 会在这个 return 之前执行 finally). 但是如果finally 中也存在 return 语句, 那么就会执行 finally 中的 return, 从而不会执行到 try 中原有的 return.
上面程序输出结果 20

  • 当catch不能捕获到try快中抛出的异常,那么后序代码将不会继续执行,(注意:这里后序代码不是try块内抛出异常后的代码,而是try-catch之后的代码)。
//省略掉finally的try-catch
public static void main(String[] args) {  int[] arr = {1, 2, 3};  try {  System.out.println("try代码块中执行前");  arr = null;  System.out.println(arr[100]);  System.out.println("try代码块中执行后");  }catch (ArrayIndexOutOfBoundsException e) {  System.out.println("这是个数组下标越界异常");  e.printStackTrace();  }  System.out.println("after try-catch-finally");  
}

执行结果如下:
在这里插入图片描述

对try-catch-finally的总结:

  1. try块内抛出异常位置之后的代码将不会被执行
  2. 如果抛出异常类型与catch时异常类型不匹配,即异常不会被成功捕获,也就不会被处理,继续往外抛,直到JVM收到后中断程序----异常是按照类型来捕获的
  3. try中可能会抛出多个不同的异常对象,则必须用多个catch来捕获----即多种异常,多次捕获
  4. 如果异常之间具有父子关系,一定是子类异常在前catch,父类异常在后catch,否则语法错误,异常的是从上到下捕获的
  5. 当finally存在时,无论是否找到匹配的异常类型, finally 中的代码都会被执行到(在该方法结束之前执行)
  6. 异常的处理:如果没有找到匹配的异常类型, 就会将异常向上传递到上层调用者;如果上层调用者也没有处理的了异常, 就继续向上传递;一直到 main 方法也没有合适的代码处理异常, 就会交给 JVM 来进行处理, 此时程序就会异常终止

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

LeetCode Hot100 | Day1 | 二叉树:二叉树的直径

LeetCode Hot100 | Day1 | 二叉树&#xff1a;二叉树的直径 主要学习内容&#xff1a; 二叉树深度求法 深度的 leftright1 得到的是从根结点到叶子结点的节点数量 543.二叉树的直径 [543. 二叉树的直径 - 力扣&#xff08;LeetCode&#xff09;](https://leetcode.cn/prob…

【韩顺平Java笔记】第8章:面向对象编程(中级部分)【262-271】

262. 回顾上一章内容 看视频 263. IDEA介绍 263.1 IDEA 介绍 IDEA 全称 IntelliJ IDEA在业界被公认为最好的 Java 开发工具IDEA 是 JetBrains 公司的产品&#xff0c;总部位于捷克的首都布拉格除了支持 Java 开发&#xff0c;还支持 HTML&#xff0c;CSS&#xff0c;PHP&am…

Qt之TCP收发图片的例子

一.效果 二.实现 1.发图片 void MainWindow::slotSendImage() {matrix.rotate(90);QPixmap tempPixmap = pixmap.transformed(matrix);QBuffer buffer;tempPixmap.save(&buffer,"jpg");ui->labelImage->setPixmap(tempPixmap);int dataLength = buffer.d…

[图形学]在半球面上均匀采样和cos加权采样

一、简介 本文介绍了如何在半球表面上进行半球面均匀采样、半球面cos加权采样采样。 给出了相关公式推导和python代码实现。 二、在半球上采样 0.预备知识 1).球面坐标系与笛卡尔坐标系 在半球面上采样时&#xff0c;常使用球面坐标系。先采样球面坐标系下的坐标参数 ( θ…

python sqlite3 工具函数

起因&#xff0c; 目的: sqlite3 最常用的函数。 比如&#xff0c;某人给了一个 database.db 文件。 但是你登录的时候&#xff0c;不知道账号密码。 此文件就是&#xff0c;查看这个数据库的详细内容。 有哪些表某个表的全部内容。添加数据 代码&#xff0c; 见注释 impor…

《数字图像处理基础》学习01-数字图像处理的相关基础知识

这篇文章只是对数字图像处理的相关基础知识有个大概的了解&#xff0c;之后的文章会接着补充和扩展。 目录 一&#xff0c;图像的基本概念 1&#xff0c;图像 2&#xff0c;图像的分类 1&#xff09;物理图像 2&#xff09;虚拟图像 二&#xff0c;数字图像处理 三&…

PostGIS--介绍

目录 1、什么是PostGIS&#xff1f;2、数据2.1 对象2.1.1 读取几何元数据信息函数2.1.2 处理点的函数2.1.3 处理线的函数2.1.4 处理面的函数2.1.5 集合 2.2 集合输入和输出2.3 shapefile文件 总结PS: 1、什么是PostGIS&#xff1f; PostGIS通过增加对空间类型、空间索引和空间…

【MaskGAN】MaskGAN: Towards Diverse and Interactive Facial Image Manipulation

文章目录 MaskGAN: Towards Diverse and Interactive Facial Image Manipulationkey points贡献方法密集映射网络DMN编辑行为模拟训练多目标学习CelebAMask-HQ数据集实验消融实验总结MaskGAN: Towards Diverse and Interactive Facial Image Manipulation 会议/期刊:CVPR 202…

实现mnist手写数字识别

基础知识 tensorflow TensorFlow是一个开源的机器学习框架&#xff0c;致力于各种数据流图的自动微分和深度神经网络的计算。简而言之&#xff0c;** TensorFlow帮助我们轻松地构建、训练和部署机器学习模型** 。它可以在各种平台上运行&#xff0c;包括桌面计算机、服务器…

Dyna-slam复现(保姆级详细图文版,百分百成功)

因最近论文要和这些算法做对比,故配置了一下,在此记录 因为是老的算法,cuda版本现在的显卡都不能使用,所以笔者找的电脑是华硕飞行堡垒17年的电脑,1080的显卡 深度学习及maskrcnn配置 先将dyna-slam git下来,终端执行 git clone https://github.com/BertaBescos/Dyna…

数据结构之红黑树实现(全)

一、红黑树 红黑树是一种自平衡的二叉搜索树&#xff0c;它通过约束节点的颜色和结构来保持平衡。红黑树是由 Rudolf Bayer 在1972年发明的&#xff0c;被认为是一种优秀的平衡树结构&#xff0c;广泛应用于各种数据结构和算法中。 1.红黑树的性质 1. 每个结点是红的或者黑的…

PhotoMaker部署文档

一、介绍 PhotoMaker&#xff1a;一种高效的、个性化的文本转图像生成方法&#xff0c;能通过堆叠 ID 嵌入自定义逼真的人类照片。相当于把一张人的照片特征提取出来&#xff0c;然后可以生成你想要的不同风格照片&#xff0c;如写真等等。 主要特点&#xff1a; 在几秒钟内…

前端工程化 - Vue

环境准备 Vue-cli是Vue官方提供的一个脚手架&#xff0c;用户快速生成一个Vue的项目模板。 Vue-cli提供了如下功能&#xff1a; 统一的目录结构本地调试热部署单元测试集成打包上线 需要安装Node.js 安装Vue-cli npm install -g vue/cli通过vue --version指令查看是否安装成…

常见排序详解(历时四天,哭了,必须释放一下)

目录 1、插入排序 1.1 基本思想 1.2 直接插入排序 1.2.1 思路 1.2.2 代码实现 1.2.3 性质 1.3 希尔排序 1.3.1 思路 1.3.2 代码实践 1.3.3 性质 2、选择排序 2.1 基本思想 2.2 直接选择排序 2.2.1 思路 2.2.2 代码实践 2.2.3 性质 2.3 堆排序 2.3.1 思路 2.…

108页PPT丨OGSM战略规划框架:实现企业目标的系统化方法论

OGSM战略规划框架是一种实现企业目标的系统化方法论&#xff0c;它通过将组织的目标&#xff08;Objectives&#xff09;、目标&#xff08;Goals&#xff09;、策略&#xff08;Strategies&#xff09;和衡量指标&#xff08;Measures&#xff09;进行系统化整合&#xff0c;确…

windows下DockerDesktop命令行方式指定目录安装

windows下DockerDesktop指定目录安装(重新安装) 因为DcokerDesktop占用内存较大, 并且拉去镜像后占用本地空间较多,所以建议安装时就更改默认安装路径和镜像存储路径 这里,展示了从下载到安装的过程: 首先下载DcokerDesktop;找到Docker Desktop Installer.exe 并重命名为 do…

国内超声波清洗机哪个品牌好?力荐四款超耐用超声波清洗机!

超声波清洗机作为一款高效实用的家庭与专业清洁利器&#xff0c;能够迅速且彻底地清洁多样化的物件。面对市场上琳琅满目的品牌与型号&#xff0c;每一款都各具特色与优势&#xff0c;故在决定购买前做足调研显得尤为重要&#xff0c;以免购入不尽如人意的产品&#xff0c;造成…

力扣110:判断二叉树是否为平衡二叉树

利用二叉树遍历的思想编写一个判断二叉树&#xff0c;是否为平衡二叉树 示例 &#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;true思想&#xff1a; 代码&#xff1a; int getDepth(struct TreeNode* node) {//如果结点不存在&#xff0c;返回…

打造自己的RAG解析大模型:Windows部署OCR服务(可商业应用)

在上一篇文章中&#xff0c;我们介绍了如何在 Windows 环境中配置 OCR 相关模型&#xff0c;并完成了模型验证。本篇文章将基于之前的内容&#xff0c;进一步讲解如何将文本检测、方向分类和文本识别模型进行串联&#xff0c;最终搭建一个基础的 OCR 应用服务。通过这些模型的串…

【Diffusion分割】CTS:基于一致性的医学图像分割模型

CTS: A Consistency-Based Medical Image Segmentation Model 摘要&#xff1a; 在医学图像分割任务中&#xff0c;扩散模型已显示出巨大的潜力。然而&#xff0c;主流的扩散模型存在采样次数多、预测结果慢等缺点。最近&#xff0c;作为独立生成网络的一致性模型解决了这一问…