JAVA-SE-异常

news2024/12/25 9:08:25

在JAVA中,将程序执行过程中发生的不正常行为称为异常。简单来说就是我们在运行或编译一段代码时所报的错误。

一,异常的体系结构

 在JAVA中不同类型的异常,都有与其对应的类来进行描述。                                                       

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

二,异常的分类

2.1 编译时异常/受查异常

编译时异常:在编译过程中发生的异常就叫编译时异常,上图所示的Exception子类中除了RuntimeException类,其他都属于编译时异常,比如不支持克隆异常。

2.2 运行时异常/非受查异常 

运行时异常:在运行时产生的异常就叫运行时异常,上图所示的RuntimeException类及其子类都是运行时异常,比如:越界,空指针,算数异常。

三,JAVA处理异常的方式 

EAFP:It's Easier to Ask Forgiveness than Permission. "事后获取原谅比事前获取许可更容易". 也就是先操作, 遇到问题再处理. 即:事后认错型

        try {
            可能出现异常的代码....
        }catch (异常1){  
            处理异常1
        }catch (异常2){
            处理异常2
        }catch (异常3){
            处理异常3
        }....

这样做的优点就是,正常流程与异常处理流程是分开来写的,程序员更关注正常流程,代码更清晰。

四,处理异常的五个关键字

JAVA中,异常处理主要的5个关键字:throw、try、catch、final、throws。

4.1 throw 和 throws 关键字

在Java中,如果出现了异常,可以借助throw关键字,抛出一个指定的异常对象,将错误信息告知给调用者,例如:


public class Test {
    public static void func(){
        int a = 0;
        if(a == 0){
            throw new ArithmeticException("a == 0");//运行时异常
        }
    }
    public static void main(String[] args) {
        func();
    }
}

 throw的使用规范:

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

public class Test {
    public static void func(){
        int a = 0;
        if(a == 0){
            throw new CloneNotSupportedException("a == 0");//编译时异常
        }
    }
    public static void main(String[] args) {
        func();
    }
}
    

那么我们怎么来处理这个异常呢?最简单的方法就是通过throws关键字来处理,实际上使用throws并没用处理该异常,只是将该异常告诉了调用此方法的人,要这个人去解决,也就是说,异常并没用消失,它只是转移到了调用者身上。例如:

public class Test {
    public static void func() throws CloneNotSupportedException {
        int a = 0;
        if(a == 0){
            throw new CloneNotSupportedException("a == 0");
        }
    }
    public static void main(String[] args) {
        func();
    }
}

 因为main 方法调用了该方法,而main方法也没有处理该异常,所以依然会报错。

throws的使用规范:

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

}

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

public class Test {
    public static void func() throws CloneNotSupportedException {
        int a = 0;
        if(a == 0){
            throw new CloneNotSupportedException("a == 0");
        }
    }
    public static void main(String[] args) throws CloneNotSupportedException {
        func();
    }
}

main方法继续抛出该异常,最后就会由JVM来处理该异常。

4.2 try - catch - finally

那么我们究竟要怎么处理异常呢?这就要提到我们上面提到的try - catch - finally了,语法格式:

try{
    可能出现异常的代码
}catch(要捕获的异常类型  e){
    处理该异常
}catch(要捕获的异常类型  e){
    处理该异常
}finally{
    一定会执行此处的代码
}//finally可加可不加,catch可以有多个

举一个例子:

public class Test {
    public static void main(String[] args) {
        try{
            System.out.println(1/0);
        }catch (ArithmeticException e){
            System.out.println("被除数不可以为0!");
        }
        System.out.println("11111");
    }
}

 1. try块内抛出异常位置之后的代码将不会被执行,例如:

public class Test {
    public static void main(String[] args) {
        try{
            System.out.println(1/0);
            System.out.println("2222");//这段代码不会执行
        }catch (ArithmeticException e){
            System.out.println("被除数不可以为0!");
        }
        System.out.println("11111");
    }
}

2.  如果抛出异常类型与所有catch的异常类型不匹配,即异常不会被成功捕获,也就不会被处理,它会继续往外抛,直到JVM收到后中断程序----异常是按照类型来捕获的

3. 当try块中可能抛出多个不同的异常时,需要用多个catch来抓捕异常,但是一旦抓捕到了第一个异常,try块出现异常后的代码就不会别执行,就是说即使后面的代码也出现了异常,也不会去处理了,例如:

public class Test {
    public static void main(String[] args) {
        try{
            //算数异常
            System.out.println(1/0);
            //下面是空指针异常,因捕获算数异常,以下代码不会执行
            int[] a = null;
            System.out.println(a.length);
            System.out.println("2222");
        }catch (ArithmeticException e){
            System.out.println("被除数不可以为0!");
        }catch (NullPointerException e){
            System.out.println("空指针异常!");
        }
        System.out.println("11111");
    }
}

如果要在一个catch中捕获多个异常,可以使用  |   ,但是不建议这么写,因为捕获的异常太模糊了,例如:

public class Test {
    public static void main(String[] args) {
        try{
            System.out.println(1/0);
            int[] a = null;
            System.out.println(a.length);
            System.out.println("2222");
        }catch (ArithmeticException | NullPointerException e){
            System.out.println("被除数不可以为0!");
        }
}

如果异常之间具有父子关系,一定是子类异常在前catch,父类异常在后catch

4. 可以通过一个catch捕获所有的异常,catch(Exception e),一次捕获(不推荐),因为捕获的异常太模糊了,不能针对性的解决问题。

有人可能发现了,我们处理异常到现在也没有用过finally ,他到底有什么用?实际上它主要的作用就是用来回收资源的,比如:Scanner,每当我们使用完Scanner时,我们都要通过 .close 来把它关闭,例如:

public class Test {
    public static void func() throws CloneNotSupportedException {
        Scanner sc = new Scanner(System.in);
        int a = sc.nextInt();
        try{
            System.out.println(1/a);
        }catch (ArithmeticException e){
            System.out.println("被除数不可以为0!");
        }finally {
            sc.close();
        }
    }
    public static void main(String[] args) throws CloneNotSupportedException {
        func();
    }
}

这时候又会有人问了,既然 finally 和 try-catch-finally 后的代码都会执行,那为什么还要有finally呢?那我将上面的代码改一改你就知道了:

public class Test {
    public static int func() throws CloneNotSupportedException {
        Scanner sc = new Scanner(System.in);
        int a = sc.nextInt();
        try{
            System.out.println(1/a);
            return a;//即使没报错,返回去了,finally中的代码也一定会执行
        }catch (ArithmeticException | NullPointerException e){
            System.out.println("被除数不可以为0!");
        }finally {
            sc.close();
            return 10;
        }
    }
    public static void main(String[] args) throws CloneNotSupportedException {
        int ret = func();//所以此时 ret = 10
    }
}

总结一下异常处理流程:

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

五,自定义异常类

要想自定义一个异常类,我们先看看JAVA是怎么定义异常类的:

 在这里我定义一个名称异常类,我们依葫芦画瓢:

public class NameException extends RuntimeException{
    public NameException() {
    }
    public NameException(String message) {
        super(message);
    }
}

我们调用一下这个类,看看行不行:

class F{
    public String name = "zhangsan";
    public void loginInfo(String userName) throws NameException{
        if (!this.name.equals(userName)) {
            throw new NameException("用户名错误!");
        }
        System.out.println("登陆成功");
    }
    public static void main(String[] args) {
        F f = new F();
        try {
            f.loginInfo("lisi");
        } catch (NameException e) {
            e.printStackTrace();//能打印哪一行出现异常
        }
    }
}

 

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

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

相关文章

实验三、数据高级查询实验

实验名称:实验3 数据高级查询实验 实验目的和要求: 实验目的和要求 掌握SQL嵌套查询和集合查询等各种高级查询的设计方法等。 实验软硬件要求: 计算机、MySQL,Navicat 实验内容、实验过程、所遇问题及其解决方法 实验内容:针…

Discourse 的用户信息中的 IP 地址显示的是 CloudFlare 的 IP 地址

因为使用了 CloudFlare 的反向地址。 所有 Discourse 获得的用户的 IP 地址其实是 CloudFlare 的服务器地址。 修改 好在 Discourse 已经提供了相关的解决方案。 需要在 Discourse 的配置文件中,添加下面的内容: “templates/cloudflare.template.ym…

分布式系统概念和设计——协调和协定

分布式系统概念和设计 协调和协定 分布式系统中的进程如何协调它们的动作和对共享值达成协议? 算法在分布式系统中的基本目的是:供一组进程来协调它们的动作或对一个或多个值达成协议 避免固定的主-从关系的主要原因是,经常需要系统即使在系统故障的情…

日志文件的轮循(logrotate)

文章目录 日志文件的轮循(logrotate)轮循基本原理轮循的基本配置实际测试logrotate的操作使用案例 自定义日志文件的轮循功能 日志文件的轮循(logrotate) 日志轮循(logrotate)是一种用于管理日志文件的工具,它可以帮助我们自动地对日志文件进…

EasyRecovery Photo16 for windows数据恢复软件免费版下载安装教程

EasyRecovery Photo16 for windows数据恢复软件免费版下载是一款由Kroll Ontrack公司开发的数据恢复软件,其主要功能是恢复已经删除或损坏的图片文件。该软件可用于恢复各种类型的图片文件,包括JPEG、GIF、BMP、PNG等,同时也支持恢复照片文件…

Thematica: 炫彩主题与黑暗奇观的Vue3之旅

✅创作者:陈书予 🎉个人主页:陈书予的个人主页 🍁陈书予的个人社区,欢迎你的加入: 陈书予的社区 🌟专栏地址: 三十天精通 Vue 3 文章目录 一、介绍1.1 博客主题和目的1.2 Vue 3简介二、炫彩主题2.1 准备工作2.2 安装必要依赖2.3 创建Vue项目2.4 设置全局样式

AJax和Axios的讲解

目录 Ajax Ajax基本介绍 同步异步 原生Ajax 原生的Ajax使用方式 Axios 基本介绍 Axios的基本使用 发送 get 请求 发送 post 请求 Axios快速入门 请求方法的别名 练习 Ajax Ajax基本介绍 Ajax: 全称Asynchronous JavaScript And XML,异步的JavaScript和XML…

【每日一题/数学模拟题/进位算术】1073. 负二进制数相加

⭐️前面的话⭐️ 本篇文章介绍【1073. 负二进制数相加】题解,算法标签:【数学】,【思维】,【模拟算术】,展示语言c/java。 📒博客主页:未见花闻的博客主页 🎉欢迎关注&#x1f50e…

代码随想录训练营Day38| 理论基础 509. 斐波那契数 70. 爬楼梯 746. 使用最小花费爬楼梯

目录 学习目标 学习内容 理论基础 509. 斐波那契数 70. 爬楼梯 746. 使用最小花费爬楼梯 学习目标 理论基础 509. 斐波那契数 70. 爬楼梯 746. 使用最小花费爬楼梯 学习内容 理论基础 problems/动态规划理论基础.md programmercarl/leetcode-master(代码随…

C++的list使用

list 1.list的介绍和使用1.1. list介绍1.2. list的使用1.2.1 list的构造1.2.2. list iterator的使用1.2.3. list capacity1.2.4 list element access1.2.5 list modifiers1.2.6 list的迭代器失效 1.list的介绍和使用 1.1. list介绍 list是可以在常数范围内在任意位置进行插入…

chatgpt赋能Python-python2的n次方

Python2中实现n次方的方法 Python是一种非常受欢迎的编程语言,其简单易学的特性吸引了大量的开发者前来学习和使用。在Python2中,实现n次方有多种方法,下面就给大家介绍一些。 方法一:使用运算符 在Python2中,可以使…

不重启Linux修改主机名,以CentOS 7举例

在 Linux 中,可以通过修改主机名配置文件的方式更改主机名,不需要重启机器即可立即生效。 下面介绍一下具体步骤: 1、查看原始主机名 比如我的主机名叫small-black 2、使用命令行修改主机名 2.1 修改主机名 首先,使用以下命…

2023年的深度学习入门指南(14) - 不能只关注模型代码

2023年的深度学习入门指南(14) - 不能只关注模型代码 最近,有一张大模型的发展树非常流行: 这个图是相当不错的,对于加深对于Transformer模型编码器、解码器作用的理解,模型的开源和闭源情况等等都相当有帮助,大家使…

尝试Google Bard并对比OpenAI ChatGPT,一个擅长创造性,一个擅长事实查询?

文章目录 尝试Google Bard并对比OpenAI ChatGPT,一个擅长创造性,一个擅长事实查询?Google Bard 的自我介绍Google Bard 暂时不支持中文Google Bard除了支持英语外,还支持日语Google Bard和OpenAI ChatGPT的对比Google Bard的回答O…

音乐宿主软件排行榜前十名,音乐宿主要买正版吗

随着电子音乐的不断发展,一些电子音乐爱好者开始尝试自己编写电子音乐。而编写电子音乐必不可少的一点就是需要一款非常好用的音乐宿主软件,那么今天我们就来说一说音乐宿主软件排行榜前十名以及音乐宿主软件要买正版吗这两个问题。 一、音乐宿主软件排…

数组【C语言】

目录 一维数组的创建和初始化 数组创建 数组的初始化 一维数组的使用 一维数组在内存中的存储 二维数组的创建与初始化 二维数组的创建 二维数组的初始化 二维数组的使用 二维数组在内存中的存储 数组越界 数组名作为函数参数 数组名 一维数组的创建和初始化 数组…

chatgpt赋能Python-python3_8降级3_6

Python3.8降级3.6,你需要知道的一切 在Python语言的世界中,每一个版本带来了新的变化和功能。但是在某些情况下,汲取早期版本的优点也是很必要的。Python3.8之前的版本当中,Python3.6是广泛使用的版本,因为它包含了许…

t检验是基于t分布的

例:鸢尾花的平均花瓣长度为3.5cm,这种说法正确吗? 可以根据假设检验的步骤,进行解决。 /设置原假设与备择假设: 原假设:μ μ0 3.5cm(说法正确) 备择假设:μ ≠ μ0 ≠…

chatgpt赋能Python-python3_8怎么安装matplotlib

Python3.8怎么安装Matplotlib Matplotlib是一个非常流行的Python可视化库,它可以用来创建各种类型的图形,包括线图、散点图、直方图、饼图和热图等等。在本文中,我们将介绍如何在Python3.8中安装Matplotlib,以及如何使用它来绘制…

chatgpt赋能Python-python3_9_0怎么安装

Python3.9.0的安装指南 Python作为目前世界上使用最广泛的编程语言之一,在数据科学、人工智能、Web开发等领域都有着广泛的应用。而今年10月5日,Python官方发布了最新的稳定版本——Python3.9.0。本文将提供一份简明的Python3.9.0安装指南。 准备工作 …