认识异常 ---java

news2024/11/29 2:42:30

目录

一. 异常的概念

二. 异常的体系结构

三. 异常的分类

三. 异常的处理

3.1 异常的抛出throw

3.2. 异常声明throws

3.3 捕获并处理try-catch

finally

 3.4异常的处理流程

四. 自定义异常类


一. 异常的概念

Java 中,将程序执行过程中发生的不正常行为称为异常。比如之前写代码时经常遇到的:
1. 算术异常
System . out . println ( 10 / 0 );
// 执行结果
Exception in thread "main" java . lang . ArithmeticException : / by zero

2. 数组越界异常

int [] arr = { 1 , 2 , 3 };
System . out . println ( arr [ 100 ]);
// 执行结果
Exception in thread "main" java . lang . ArrayIndexOutOfBoundsException : 100

3. 空指针异常

int [] arr = null ;
System . out . println ( arr . length );
// 执行结果
Exception in thread "main" java . lang . NullPointerException

点进去任意一个异常, 我们发现:

从上述代码中可以看到,java中不同类型的异常,都有与其对应的类来进行描述 

二. 异常的体系结构

从上图中可以看到:
1. Throwable 是异常体系的顶层类,其派生出两个重要的子类 , Error Exception
2. Error 指的是 Java 虚拟机无法解决的严重问题,比如: JVM 的内部错误、资源耗尽等 ,典型代表: StackOverflowError OutOfMemoryError ,一旦发生回力乏术。
3. Exception 异常产生后程序员可以通过代码进行处理,使程序继续执行。比如:感冒、发烧。我们平时所说的异常就是Exception

三. 异常的分类

异常可能在编译时发生,也可能在程序运行时发生,根据发生的时机不同,可以将异常分为:

1. 编译时异常

在程序编译期间发生的异常,称为编译时异常,也称为受检查异常(Checked Exception)  

例: 

我们可以通俗的来理解, 在编写代码的过程中, 出现了红色的波浪线, 此时的异常就叫做编译时异常或受查异常.

2. 运行时异常

在程序执行期间发生的异常,称为运行时异常,也称为非受检查异常 (Unchecked Exception)
RunTimeException 以及其子类对应的异常,都称为运行时异常 。例如上述我们举例的之前见过的异常: NullPointerException 、 ArrayIndexOutOfBoundsException、 ArithmeticException
注意:编译时出现的语法性错误,不能称之为异常。例如将 System.out.println 拼写错了 , 写成了
system.out.println. 此时编译过程中就会出错 , 这是 " 编译期 " 出错。而运行时指的是程序已经编译通过得到 class 文件了 , 由 JVM 执行过程中出现的错误.

三. 异常的处理

异常处理主要的 5 个关键字: throw try catch finally throws

3.1 异常的抛出throw

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

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

一般情况下, 通过throw抛出的是 自定义的异常, 可以自己通过类定义异常并抛出

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

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. 异常一旦抛出,其后的代码就不会执行

3.2. 异常声明throws

处在方法声明时参数列表之后,当方法中抛出编译时异常,用户不想处理该异常,此时就可以借助 throws 将异常抛给方法的调用者来处理。即当前方法不处理异常,提醒方法的调用者处理异常
语法格式:
修饰符 返回值类型 方法名 ( 参数列表 ) throws 异常类型 1 ,异常类型 2 ...{
}

意思为:在这个方法中, 可能会包含这些异常, 告诉调用这个方法的人也就是程序猿去处理这些异常

如果程序猿不对异常进行处理, 那么就会交给JVM处理, 程序就会立刻停止.

 注意事项

1. throws 必须跟在方法的参数列表之后
2. 声明的异常必须是 Exception 或者 Exception 的子类
3. 方法内部如果抛出了多个异常, throws 之后必须跟多个异常类型,之间用逗号隔开,如果抛出多个异常类型具有父子关系,直接声明父类即可。

因为ArithmeticException是RuntimeException的子类, 所以只用写父类即可, 即:

4. 调用声明抛出异常的方法时,调用者必须对该异常进行处理,或者继续使用throws抛出

把光标方法波浪线处, 使用Alt+Enter 可以使用快捷键

 5. 如果throw Exception

这里的Exception是包含两种类型, 编译时异常和运行时异常, 所以编译器默认调用func()引发的是编译时异常  在main方法后也加上throw Exception, 此时才可能会变成运行时异常, 上JVM处理

3.3 捕获并处理try-catch

throws 对异常并没有真正处理,而是将异常报告给抛出异常方法的调用者,由调用者处理。如果真正要对异常进行处理,就需要try-catch
语法格式:
try {
        // 将可能出现异常的代码放在这里
} catch ( 要捕获的异常类型 e ){
        // 如果 try 中的代码抛出异常了,此处 catch 捕获时异常类型与 try 中抛出的异常类型一致时,或者是 try 中抛出异常的基类时,就会被捕获到
        // 对异常就可以正常处理,处理完成后,跳出 try-catch 结构,继续执行后序代码
}[ catch ( 异常类型 e ){
        // 对异常进行处理
        // 异常的处理方式
        //System.out.println(e.getMessage()); // 只打印异常信息
        //System.out.println(e); // 打印异常类型:异常信息
        e . printStackTrace (); // 打印信息最全面
} ]
// 后序代码
// 当异常被捕获到时,异常就被处理了,这里的后序代码一定会执行
// 如果捕获了,由于捕获时类型不对,那就没有捕获到,这里的代码就不会被执行
注意:
1. [] 中表示可选项,可以添加,也可以不用添加
2. try 中的代码可能会抛出异常,也可能不会

例:

 try中的代码发生数组越界, 通过数组越界异常进行捕捉, 所以捕捉到了, 就可以对异常进行处理, 处理后跳出try-catch结构, 继续执行后续代码, 所以运行结果为:

 若捕捉的是空指针异常:

即并未捕捉到, 所以就没有处理数组越界异常, 则交给JVM处理, 程序将立刻停止, 什么也不会打印

想要捕获数组越界异常, 继续catch, 自动匹配

第二种写法:(不推荐)

第三种写法:(不推荐)

注: 

1. 在try中发生异常后的代码不会被执行

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

 

finally

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

 语法格式:

try {
        // 可能会发生异常的代码
} catch ( 异常类型 e ){
        // 对捕获到的异常进行处理
} finally {
        // 此处的语句无论是否发生异常,都会被执行到
}
        // 如果没有抛出异常,或者异常被捕获处理了,这里的代码也会执行

未发生异常:

 发生异常:

 体会资源回收:

另一种写法:

光标放在try上, Alt+Enter

注意:finally中的代码一定会执行的,一般在finally中进行一些资源清理的扫尾工作

// 下面程序输出什么?
public static void main ( String [] args ) {
        System . out . println ( func ());
}
public static int func () {
        try {
                return 10 ;
        } finally {
                return 20 ;
        }
}

//20

finally 执行的时机是在方法返回之前 (try 或者 catch 中如果有 return 会在这个 return 之前执行 finally). 但是如果finally 中也存在 return 语句 , 那么就会执行 finally 中的 return, 从而不会执行到 try 中原有的 return.
一般我们不建议在 finally 中写 return ( 被编译器当做一个警告 ).

 3.4异常的处理流程

首先了解一个概念:调用栈

调用栈:

方法之间是存在相互调用关系的, 这种调用关系我们可以用 "调用栈" 来描述. 在 JVM 中有一块内存空间称为"虚拟机栈" 专门存储方法之间的调用关系. 当代码中出现异常的时候, 我们就可以使用 e.printStackTrace(); 的方式查看出现异常代码的调用栈.  如果本方法中没有合适的处理异常的方式 , 就会沿着调用栈向上传递

 看下述代码:

在main方法中调用了func(), 在func()中出现了数组越界异常, 但是在func()方法中并没有处理异常, 于是沿着沿着调用栈向上传递到main方法中, 发现在main方法中处理了该异常, 所以不会交给JVM处理, 输出的结果为:

异常处理流程总结
1. 程序先执行 try 中的代码
2. 如果 try 中的代码出现异常 , 就会结束 try 中的代码 , 看和 catch 中的异常类型是否匹配 .
3. 如果找到匹配的异常类型 , 就会执行 catch 中的代码
4. 如果没有找到匹配的异常类型 , 就会将异常向上传递到上层调用者 .
5. 无论是否找到匹配的异常类型 , finally 中的代码都会被执行到 ( 在该方法结束之前执行 ).
6. 如果上层调用者也没有处理的了异常 , 就继续向上传递 .
7. 一直到 main 方法也没有合适的代码处理异常 , 就会交给 JVM 来进行处理 , 此时程序就会异常终止 .

 

四. 自定义异常类

Java 中虽然已经内置了丰富的异常类 , 但是并不能完全表示实际开发中所遇到的一些异常,此时就需要维护符合我 们实际情况的异常结构.
例如 实现一个用户登陆功能

 此时, 虽然我们可以很快的找到错误所在, 但代码一多, 就很难找到了, 所以, 我们要自定义异常类来帮助我们更快找到错误.

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

自定义异常类:

 接下来, 通过throw自己抛异常

 虽然, 我们抛出了异常, 但是为了使程序正常运行, 我们需要对异常进行处理:

今天的分享就到这里, 谢谢大家的点赞支持!! 

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

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

相关文章

CPP-SCNUOJ-Problem P24. [算法课贪心] 跳跃游戏

Problem P24. [算法课贪心] 跳跃游戏 给定一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。 数组中的每个元素代表你在该位置可以跳跃的最大长度 判断你是否能够到达最后一个下标。 输入 输入一行数组nums 输出 输出true/fasle 样例 标准输入 2 3 1 …

出海风潮:中国母婴品牌征服国际市场的机遇与挑战!

近年来&#xff0c;中国母婴品牌在国内市场蓬勃发展的同时&#xff0c;也逐渐将目光投向国际市场。这一趋势不仅受益于中国经济的崛起&#xff0c;还得益于全球市场对高质量母婴产品的不断需求。然而&#xff0c;面对国际市场的机遇&#xff0c;中国母婴品牌同样面临着一系列挑…

Myblog02-基于ssm,springboot的改进

目录 一、项目概述&#xff1a; 应用技术&#xff1a; 接口实现&#xff1a; 数据库建表&#xff0c;sql脚本&#xff1a; 页面展示&#xff1a;登陆页面 项目源码&#xff1a;myblog01: 初版的个人博客项目-使用基本的javaWeb (gitee.com) 二、对博客系统进行测试 总结…

深入分析爬虫中time.sleep和Request的并发影响

背景介绍 在编写Python爬虫程序时&#xff0c;我们经常会遇到需要控制爬取速度以及处理并发请求的情况。本文将深入探讨Python爬虫中使用time.sleep()和请求对象时可能出现的并发影响&#xff0c;并提供解决方案。 time.sleep()介绍 首先&#xff0c;让我们来了解一下time.s…

【发布小程序配置服务器域名,不配置发布之后访问就会报错request:fail url not in domain list】

小程序在本地开发的时候大家通常会在微信开发者工具中设置“不校验合法域名、web-view (业务域名)、TLS 版本以及HTTPS证书”&#xff0c;久而久之可能会忘掉这个操作&#xff0c;然后打包直接上线发布&#xff0c;结果发现访问会报错request:fail url not in domain list&…

CETN03 - The Evolution of Computers

文章目录 I. IntroductionII. First Modern Digital Computer: ENIAC (1946)III. First Generation ComputerIV. Second Generation ComputerV. Third Generation ComputerVI. Fourth Generation ComputerVII. ConclusionI. 引言II. 第一台现代数字计算机&#xff1a;ENIAC&…

自定义 el-select 和 el-input 样式

文章目录 需求分析el-select 样式el-input 样式el-table 样式 需求 自定义 选择框的下拉框的样式和输入框 分析 el-select 样式 .select_box{// 默认placeholder:deep .el-input__inner::placeholder {font-size: 14px;font-weight: 500;color: #3E534F;}// 默认框状态样式更…

C++ 12.5作业

以下是一个简单的比喻&#xff0c;将多态概念与生活中的实际情况相联系&#xff1a; 比喻&#xff1a;动物园的讲解员和动物表演 想象一下你去了一家动物园&#xff0c;看到了许多不同种类的动物&#xff0c;如狮子、大象、猴子等。现在&#xff0c;动物园里有一位讲解员&…

库函数qsort的使用及利用冒泡排序模拟实现qsort

文章目录 &#x1f680;前言&#x1f680;void*类型指针&#x1f680;库函数qsort的使用&#x1f680;利用冒泡排序实现库函数qsort() &#x1f680;前言 今天阿辉将为大家介绍库函数qsort的使用&#xff0c;还包括利用冒泡排序模拟实现qsort以及void*类型的指针&#xff0c;关…

云祺副本容灾机制讲解

副本&#xff0c;顾名思义就是一份数据的拷贝。 在系统中&#xff0c;将数据的目的分为了三种&#xff1a;备份、副本和归档。 其中备份数据&#xff0c;通常是存放在备份系统本地&#xff0c;或数据中心本地&#xff1b;副本数据通过是存放在异地的备份系统中&#xff0c;或…

【C语言】【堆排序实现TOPK问题】写一个堆排序,并且在一百万个数中找出最大的前K个

1.堆排序的实现&#xff1a; 如果要升序输出&#xff0c;则实现大堆 如果要降序输出&#xff0c;则实现小堆 逻辑&#xff1a;&#xff08;升序输出&#xff09; 将堆顶的元素和最后一个元素交换位置&#xff0c;此时左子树和右子树分别仍是大堆的顺序&#xff0c;交换位置后…

车企数据治理实践案例,实现数据生产、消费的闭环链路 | 数字化标杆

随着业务飞速发展&#xff0c;某汽车制造企业业务系统数量、复杂度和数据量都在呈几何级数的上涨&#xff0c;这就对于企业IT能力和IT架构模式的要求越来越高。加之企业大力发展数字化营销、新能源车等业务&#xff0c;希望通过持续优化客户体验&#xff0c;创造可持续发展的数…

leetcode:统计感冒序列的数目【数学题:组合数含逆元模版】

1. 题目截图 2.题目分析 需要把其分为多个段进行填充 长为k的段&#xff0c;从两端往中间填充的方案数有2 ** (k - 1)种 组合数就是选哪几个数填哪几个段即可 3.组合数含逆元模版 MOD 1_000_000_007 MX 100_000# 组合数模板 fac [0] * MX fac[0] 1 for i in range(1, MX…

一个完整的转录组分析流程

本期的教程代码&#xff08;部分&#xff09; #!/bin/bash # # 使用fastq-dump解压sra数据 # 本数据集为双端数据 # 解压格式为fq.gz for i in SRR6929571 SRR6929572 SRR6929573 SRR6929574 SRR6929577 SRR6929578; do pfastq-dump --split-files --threads 20 --gzip -s 00_…

综合指南:如何创建有效的知识地图?

知识地图是知识管理中的重要工具&#xff0c;使企业能够有效地利用其资产。它促进了解决问题、新人整合和组织学习。此外&#xff0c;它还提高了生产力&#xff0c;实现了数据驱动的决策&#xff0c;并优化了流程。通过捕获和组织有价值的知识资产&#xff0c;它确保了专业知识…

如何通过nvm安装多版本nodejs?如果nodejs安装成功,但npm安装失败怎么办?

我们在开发项目的时候&#xff0c;最开始&#xff0c;是只有一个老的项目&#xff0c;老项目单独安装了node版本4.4.7&#xff0c;后来有了新项目&#xff0c;由于有两个项目&#xff0c;但是一个需要老一些版本的node&#xff0c;一个需要新版本的node&#xff0c;因此需要在两…

签名应用APP分发平台的微服务化部署是什么?其有哪些优势?

在信息技术的世界里&#xff0c;软件开发和部署的模式不断演进。从单体架构到服务化&#xff0c;再到今日备受瞩目的微服务架构。微服务化部署作为一种新兴的软件架构风格&#xff0c;正被越来越多的企业采用。它使得应用可以被分解成一套相互独立的最小服务单元。而“分发平台…

数据结构与算法编程题39

数组A[]中有 n 个整数&#xff0c;没有次序&#xff0c;数组从下标1开始存储&#xff0c;请写出顺序查找任一元素k的算法 &#xff0c;若查找成功&#xff0c;则返回元素在数组中的位置&#xff1b;若查找不成功&#xff0c;则返回 0。 /*数组A[]中有 n 个整数&#xff0c;没有…

Citrix 退出中国市场!华为云以三大优势继续称霸桌面云江湖

文 | 智能相对论 作者 | 沈浪 又一家美国科技企业败走中国市场&#xff01; 前不久&#xff0c;美国虚拟化巨头思杰系统&#xff08;Citrix System&#xff09;公司发布公告&#xff0c;“已决定停止在中国市场&#xff08;包括香港地区和澳门地区&#xff09;的所有新的商业…

JS小技巧,如何去重对象数组?

关于数组对象去重的业务场景&#xff0c;想必大家都遇到过类似的需求吧&#xff0c;这对这样的需求你是怎么做的呢。下面我就先和大家分享下如果是基于对象的1个属性是怎么去重实现的。 方法一&#xff1a;使用 .filter() 和 .findIndex() 相结合的方法 使用 Array.prototype.…