Java体系中的异常

news2024/10/7 2:42:23

在这里插入图片描述

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.coloradmin.cn/o/2193416.html

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

相关文章

三菱FX3UPLC定位模式介绍

运行模式的比较 *1用相对定位指令代替。 *2使用相对/绝对定位指令。 *3使用直线插补指令的连续路径功能。 *4使用直线插补指令的连续路径功能。 可单轴运行。 *5.使用表格运行(连续运行功能)。 *6.使用中断定位指令。 *7只支持FX3UFX3UC可编程控制器&#xff0c;使用可变速脉…

设计模式之装饰器模式(Decorator)

一、装饰器模式介绍 装饰模式(decorator pattern) 的原始定义是&#xff1a;动态的给一个对象添加一些额外的职责。 就扩展功能而言&#xff0c;装饰器模式提供了一种比使用子类更加灵活的替代方案。 在软件设计中&#xff0c;装饰器模式是一种用于替代继承的技术&#xff0c;它…

Java语法之异常

1.异常的概念以及体系结构 1.1 异常的概念 在生活中人会生病,比如咳嗽流鼻涕,头晕等,程序也一样,比如:数据格式不匹配,网络不通畅,内存报警等.在Java中,我们把程序执行的不正常行为称为异常. 比如: 1. 算数异常 System.out.println(10 / 0); // 执行结果 Exception in thread &…

python导出requirements.txt的几种方法

整理了python导出requirements.txt的几种方法和流程 Condapippipreqs 最近又碰到整理requirements.txt的问题&#xff0c;有好几种命令可以做到这一点&#xff0c;但是之前整理的时候会输出一堆乱七八糟的包&#xff0c;这次挨个试了所有方法&#xff0c;特此记录。我的平台是a…

【本地缓存】Java 中的 4 种本地缓存

目录 1、手写一个简单的本地缓存1.1、封装缓存实体类1.2、创建缓存工具类1.3、测试 2、Guava Cache2.1、Guava Cache 简介2.2、入门案例2.2.1、引入 POM 依赖2.2.2、创建 LoadingCache 缓存 2.3、Guava Cache 的优劣势和适用场景 3、Caffeine3.1、Caffeine 简介3.2、对比 Guava…

elasticsearch ES DBA常用语句

一、 查看集群状态 curl -uelastic 连接串:端口/_cluster/health?pretty 集群健康有三种状态&#xff1a;green,yellow,red green&#xff1a;所有主要分片、复制分片都可用yellow&#xff1a;所有主要分片可用&#xff0c;但不是所有复制分片都可用red&#xff1a;不是所有…

基于SSM的学生信息管理系统【附源码】

​基于SSM的学生信息管理系统&#xff08;源码L文说明文档&#xff09; 目录 4 系统设计 4.1界面设计原则 4.2功能结构设计 4.3数据库设计 4.3.1数据库概念设计 4.3.2 数据库物理设计 第5章 系统实现 5.1管理员功能实现 5.1.1班级和课程关…

基于企业现状定制化的数字化转型路径和战略性架构规划

如何从企业现状出发规划数字化转型 随着技术的迅猛发展&#xff0c;全球企业都在加速推进数字化转型&#xff0c;以增强市场竞争力并提升运营效率。数字化转型并不是一个统一的模板&#xff0c;它要求企业结合自身的业务现状、行业环境和技术基础&#xff0c;制定个性化的转型…

通信工程学习:什么是B/S浏览器服务器模式

B/S&#xff1a;浏览器服务器模式 B/S&#xff08;Browser/Server&#xff0c;浏览器/服务器&#xff09;模式&#xff0c;又称B/S结构&#xff0c;是Web兴起后的一种网络结构模式。在这种模式中&#xff0c;Web浏览器是客户端最主要的应用软件&#xff0c;系统功能实现的核心部…

分享一个基于.net的学生信息管理系统 C#高校教务管理系统(源码、调试、LW、开题、PPT)

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人 八年开发经验&#xff0c;擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等&#xff0c;大家有这一块的问题可以一起交流&…

计算机毕业设计 智慧物业服务系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

初学Vue(2)

文章目录 监视属性 watch深度监视computed 和 watch 之间的区别 绑定样式&#xff08;class style&#xff09;条件渲染列表渲染基本列表key的原理列表过滤列表排序收集表单中的数据 v-model过滤器&#xff08;Vue3已移除&#xff09; 监视属性 watch 当被监视的属性变化时&am…

使用frp将树莓派穿透到外网

引言 frp官网 最近买了一块树莓派 zero 2w&#xff0c;想要它可以进行远程访问&#xff0c;所以想到了frp这个方案进行穿透&#xff0c;后期会使用树莓派搭建音乐服务器&#xff0c;本人手机内存有点小&#xff0c;xxxx云音乐太占空间&#xff0c;有兴趣的话可以关注后续。 …

在 window 系统下安装 Ubuntu (虚拟机)

文章目录 零、Ubuntu 和 Vmware workstation 资源一、下载 Ubuntu二、下载 Vmware Workstation Pro三、安装 Vmware Workstation Pro四、创建虚拟机五、配置 Ubuntu 零、Ubuntu 和 Vmware workstation 资源 如果觉得自己下载 Ubuntu 和 Vmware workstation 麻烦&#xff0c;也…

如何在 MySQL 中实现数据压缩

如何在 MySQL 中实现数据压缩 在 MySQL 数据库中&#xff0c;数据压缩可以帮助节省存储空间和提高数据传输效率。本篇文章我就一起来看看关于MySQL数据压缩的相关内容。 一、为什么需要数据压缩 随着数据量的不断增长&#xff0c;数据库的存储空间需求也在不断增加。数据压缩…

【Blender Python】1.概述和基础使用

概述 众所周知&#xff0c;Blender是一款开源免费的3D建模软件&#xff08;当然不限于3D建模&#xff09;。在Blender中&#xff0c;可以使用其内置的Python解释器执行Python代码&#xff0c;用于程序化的生成网格以及其他内容。你可以基于此创建Blender插件。 这个系列就是快…

gets和puts

今天我们来学习一组新的函数 gets和puts&#xff0c;它们分别对应的是scanf和printf&#xff0c;但在功能和其它方面有着一些差异 1.gets函数 1.char*gets(char*str); 函数功能&#xff1a;简单来说就像上面的格式一样&#xff0c;给他一个地址&#xff08;送快递总是要留一个…

Omron/TCP 通信过程

1. 首先 TCP 三次握手 2. 客户端向服务器申请节点地址 客户端向服务器发送一个包含Client Node Address字段的数据包 申请节点地址。由于客户端申请的时候还没有节点地址&#xff0c;因此该字段被置为0x00000000。 3. 服务器向客户端确认收到申请 服务器向客户端发送一个确认…

SQL第12课挑战题

1. 返回customers表中的顾客名称&#xff08;cust_name)和Orders表中的相关订单号&#xff08;order_num)&#xff0c;并按顾客名称再按订单号对结果进行排序。实际上是尝试两次&#xff0c;一次使用简单的等联结语法&#xff0c;一次使用inner join. 2. 让上一题变得更有用一些…

【算法篇】回溯算法类(2)(笔记)

目录 一、LeetCode 题目 1. 子集II 2. 递增子序列 3. 全排列 4. 全排列 II 5. 重新安排行程 6. N皇后 7. 解数独 二、题目思路整理 一、LeetCode 题目 1. 子集II https://leetcode.cn/problems/subsets-ii/description/https://leetcode.cn/problems/subsets-ii/des…