[Java基本语法] 异常

news2025/4/26 20:55:32

🌸个人主页:https://blog.csdn.net/2301_80050796?spm=1000.2115.3001.5343
🏵️热门专栏:🍕 Collection与数据结构 (92平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm=1001.2014.3001.5482
🧀线程与网络(96平均质量分) https://blog.csdn.net/2301_80050796/category_12643370.html?spm=1001.2014.3001.5482
🍭MySql数据库(93平均质量分)https://blog.csdn.net/2301_80050796/category_12629890.html?spm=1001.2014.3001.5482
🍬算法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12676091.html?spm=1001.2014.3001.5482
感谢点赞与关注~~~
在这里插入图片描述

目录

  • 1. 异常
    • 1.1 异常的概念与体系结构
      • 1.1.1 异常的概念
      • 1.1.2 异常的体系结构
      • 1.1.3 异常的分类
    • 1.2 异常的处理
      • 1.2.1 防御式编程
      • 1.2.2 异常的抛出
      • 1.2.3 异常的捕获
        • 1.2.3.1 异常throws声明
        • 1.2.3.2 捕获并处理
        • 1.2.3.3 finally
      • 1.2.4 异常处理的流程 (总结)
    • 1.3 自定义异常

1. 异常

1.1 异常的概念与体系结构

1.1.1 异常的概念

在我们的生活中,一个人如果表情痛苦,我们可能会问: 你是生病了吗? 需要我陪你去看医生吗?
在这里插入图片描述
程序也和人是一样的,均会发生一些"生病"的行为,比如: 数据格式不对, 数组越界,网络中断等, 我们把这种程序出现的"生病"行为称为"异常".比如在我们之前写代码经常遇到的"报红",大多数都是异常.

  1. 算数异常
    在这里插入图片描述
  2. 数组越界异常
    在这里插入图片描述
  3. 空指针异常
    在这里插入图片描述
    从上述的展示中可以看出,异常也分不同的类型,都有与其对应的类来进行描述,总的来说,异常本质上是一种类.

1.1.2 异常的体系结构

异常的种类很多,为了对不同类型的异常或错误进行更好的管理,Java内部制定了异常的体系结构:
在这里插入图片描述

从上图中我们可以看到:

  1. Throwable是异常体系的顶层类,由它派生出了两个子类:Error和Exception,即错误和异常.
  2. Error:指的是Java虚拟机无法解决的严重问题,如JVM内部错误,资源耗尽等,典型代表就是StackOverflowError(栈溢出错误).
  3. Exception: 异常产生后程序员可以通过修改代码进行处理,可以使得程序继续执行.

1.1.3 异常的分类

根据异常发生的时间不同,我们可以将异常分为:

  1. 编译时异常
    在程序编译期间发生的异常,称为编译时异常,也称为受查异常,我们在用idea编译器时,编译器会在出现异常的语句下面划红线.
 public class Person {
        private int age;
        private String name;

        public Person(int age, String name) {
            this.age = age;
            this.name = name;
        }
    @Override
        protected Object clone() {
            return super.clone();
        }
}

在这里插入图片描述
从上述的代码我们可以看出,在clone方法之后我们没有对发生的异常进行声明,所以在放重写的方法那里产生了编译时异常,在clone下面划了红线.

  1. 运行时异常
    在程序执行的期间发生的异常,称为运行时异常,也称为非受查异常,RunTimeException以及子类对应的异常,都叫运行时异常,比如我们上面提到的: 算数异常(ArithmeticException),空指针异常(NullPointerException),数组越界异常(ArraryIndexOutOfBoundsException).

1.2 异常的处理

1.2.1 防御式编程

错误在代码中是客观存在的.此时就需要把出现的错误和异常及时通知程序员,主要有以下两种方式:

  1. LBYL: look before your leap. 在操作之前就进行充分的检查,即:事前防御,语法格式如下:
boolean ret = false;
ret = 操作1;
if(!ret){
	处理异常1;
	return;
}
ret = 操作2;
if(!ret){
	处理异常2;
	return;
}
......

缺点: 正常的流程和错误的处理混在一起,代码显得比较凌乱.
2. EAFP: It’s Easier to ask forgiveness than permission. 事后获取原谅比事前获取许可更容易.也就是先操作,遇到的问题放在最后一起处理,即:事后认错型.

try{
	操作1;
	操作2;
	......
}catch(异常1){
	处理异常1;
}catch(异常2){
	处理异常2;
}
.......

优势: 正常的流程和错误的处理是分开的,代码更加清晰,容易理解.
异常处理的核心思想就是EAFP
在Java中,处理异常主要有5个关键字: throw, try, catch, finally , throws.

1.2.2 异常的抛出

在编写程序时, 如果程序中出现错误, 此时就需要将错误的信息报告给调用者.
在Java中,可以使用throw关键字,抛出一个指定的异常对象,来将错误信息来报告给调用者.具体语法格式如下:

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

我们举一个例子来说明:例如我们要获取数组任意位置的元素和方法.

public static int getElement(int[] array,int index){
        if (array == null){
            throw new NullPointerException("element of array is null");
        }
        if (index > array.length-1||index < 0){
            throw new ArrayIndexOutOfBoundsException("index is out of array");
        }
        return array[index];
    }
public static void main(String[] args) {
        int[] array = {1,2,3};
        getElement(array,3);
        int[] array2 = null;
        getElement(array2,2);
    }

在这里插入图片描述
在这里插入图片描述
[注意事项]:

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

1.2.3 异常的捕获

异常的捕获,通常有两种: 异常的throws声明以及try-catch捕获处理

1.2.3.1 异常throws声明

处于方法声明的参数表之后,当方法中抛出编译时异常,用户不想处理该异常,此时就可以借助throws将异常抛给调用者来处理,即当前方法不处理异常,提醒方法的调用者处理该异常.若调用者没有处理或throws,就会报错,语法格式如下:

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

}

下面我们拿我们上面提到的clone方法来举例

public class Person {
        private int age;
        private String name;

        public Person(int age, String name) {
            this.age = age;
            this.name = name;
        }
    @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
}
public class MyException {
    public static void main(String[] args)throws CloneNotSupportedException {
        Person p1 = new Person(12,"zhangsan");
        Person p2 = (Person) p1.clone();
    }
}

在这里插入图片描述
上述的代码我们可以看出如果我们在main方法调用clone方法的时候也没有直接处理异常,把异常throws了,该异常就会交给jvm来处理,若处理失败,程序会在出现异常的地方立即终止.
我们对上述代码进行一定地修正

public class Person implements Cloneable {
        private int age;
        private String name;

        public Person(int age, String name) {
            this.age = age;
            this.name = name;
        }
    @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
}
public class MyException {
    public static void main(String[] args) throws CloneNotSupportedException{
        Person p1 = new Person(12,"zhangsan");
        Person p2 = (Person) p1.clone();
    }
}

上述代码我们对Person实现了Cloneable接口,jvm处理异常成功,程序运行之后便不会报错.

[注意事项]

  1. throws必须跟在方法的参数列表之后.
  2. 声明的异常必须是Exception或者是Exception的子类.
  3. 方法内部如果有多个异常,throws之后必须跟上多个异常,之间用逗号隔开,若抛出的异常具有父子关系,直接声明父类即可.
public static int getElement(int[] array,int index) throws RuntimeException{//声明运行时异常即可
        if (array == null){
            throw new NullPointerException("element of array is null");
        }
        if (index > array.length-1||index < 0){
            throw new ArrayIndexOutOfBoundsException("index is out of array");
        }
        return array[index];
    }

  1. 调用抛出异常的方法时,必须对异常进行处理,或者继续使用throws抛出.
public static int getElement(int[] array,int index) throws RuntimeException{
        if (array == null){
            throw new NullPointerException("element of array is null");
        }
        if (index > array.length-1||index < 0){
            throw new ArrayIndexOutOfBoundsException("index is out of array");
        }
        return array[index];
    }
public static void main(String[] args) throws RuntimeException{
       int[] array = {1,2,3};
       getElement(array,3);
       int[] array2 = null;
       getElement(array2,2);
 }
1.2.3.2 捕获并处理

throws对异常并没有真正处理,而是将异常报告给抛出异常方法的调用者,由调用者处理。如果真正要对异常进行处理,就需要try-catch.
语法格式如下:

try{
	操作1;
	操作2;
}catch(异常1){
	处理异常1;
}catch(异常2){
	处理异常2;
}finally{
    此处的代码一定会被执行
}
//后续代码

如果捕获异常成功,并且异常被处理成功,会跳出try-catch结构,之后的代码也会被执行,若有异常没有被捕获到,后续的代码就不会被执行.我们下面举个例子:

public static int getElement(int[] array,int index){
        if (array == null){
            throw new NullPointerException("element of array is null");
        }
        if (index > array.length-1||index < 0){
            throw new ArrayIndexOutOfBoundsException("index is out of array");
        }
        return array[index];
    }
    public static void main(String[] args) {
        try {
            int[] array = {1,2,3};
            getElement(array,3);
        }catch (ArrayIndexOutOfBoundsException e){
            System.out.println("处理了数组越界异常");
        }
        System.out.println("异常处理结束,后续代码被执行");
    }

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

[注意事项]

  1. try代码块中,如果有一个地方抛出了异常,这个地方之后的代码不会被执行.
public static int getElement(int[] array,int index) throws RuntimeException{
        if (array == null){
            throw new NullPointerException("element of array is null");
        }
        if (index > array.length-1||index < 0){
            throw new ArrayIndexOutOfBoundsException("index is out of array");
        }
        return array[index];
    }
    public static void main(String[] args) {
        try {
            int[] array = {1,2,3};
            getElement(array,3);
            int[] array2 = null;
            getElement(array2,2);
        }catch (NullPointerException e){
            System.out.println("处理了空指针异常");
        }catch (ArrayIndexOutOfBoundsException e){
            System.out.println("处理了数组越界异常");
        }
        System.out.println("异常处理结束,后续代码被执行");
    }

在这里插入图片描述
由此可见,运行结果中并,没有打印空指针异常.即可说明上述一点.
2. 如果异常类型与catch时的异常类型不匹配,异常就不会被捕获成功,也不会被处理,继续抛出,知道JVM收到后终止.

ublic static void main(String[] args) {
        try {
            int[] array = {1,2,3};
            getElement(array,3);
        }catch (NullPointerException e){
            System.out.println("处理了空指针异常");
        }
        System.out.println("异常处理结束,后续代码被执行");
    }
    public static int getElement(int[] array,int index) throws RuntimeException{
        if (array == null){
            throw new NullPointerException("element of array is null");
        }
        if (index > array.length-1||index < 0){
            throw new ArrayIndexOutOfBoundsException("index is out of array");
        }
        return array[index];
    }

在这里插入图片描述
3. try中可能会有多个异常,必须用多个catch来捕获

public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        try {
            System.out.println("before");
            arr = null;
            System.out.println(arr[100]);
            System.out.println("after");
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("这是个数组下标越界异常");
            e.printStackTrace();
        } catch (NullPointerException e) {
            System.out.println("这是个空指针异常");
            e.printStackTrace();
        }
        System.out.println("after try catch");
    }

若多个异常的处理方式完全相同,也可以写成这样:

catch (ArrayIndexOutOfBoundsException|NullPointerException){
......
}
  1. 如果异常之间有父子关系,一定是子类在前,父类在后.
public static void main(String[] args) {
        try {
            int[] array = {1,2,3};
            getElement(array,3);
        }catch (Exception e){
            System.out.println("处理了异常");
        }catch (ArrayIndexOutOfBoundsException e){
            System.out.println("处理了数组越界异常");
        }
        System.out.println("异常处理结束,后续代码被执行");
    }

在这里插入图片描述
数组越界异常已经被第一个catch处理了,该异常的捕获类型属于数组越界处理的父类,而后面的子类没有处理到,所以会报错.

1.2.3.3 finally

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

语法格式:
try{
	// 可能会发生异常的代码
}catch(异常类型 e){
	// 对捕获到的异常进行处理
}finally{
	// 此处的语句无论是否发生异常,都会被执行到
}
	// 如果没有抛出异常,或者异常被捕获处理了,这里的代码也会执行
public static void main(String[] args) {
        try {
            int[] array = {1,2,3};
            getElement(array,3);
        }catch (NullPointerException e){
            System.out.println("处理了空指针异常");
        }finally {
            System.out.println("一定会被执行");
        }
        System.out.println("异常处理结束,后续代码被执行");
    }

在这里插入图片描述
我们从上述执行结果可以看到,无论异常有没有被捕获到,finally一定会被执行到.
finally的代码一般用来进行一些资源清理的扫尾工作.例如:

public class TestFinally {
	public static int getData(){
		Scanner sc = null;
	try{
		sc = new Scanner(System.in);
		int data = sc.nextInt();
		return data;
	}catch (InputMismatchException e){
		e.printStackTrace();
	}finally {
		if(null != sc){
		sc.close();
	}
	return 0;
}

从上述代码中,我们知道如果sc被成功调用,直接返回了,若没有finally语句,sc的资源没有进行关闭,造成了资源泄露.

面试题

  1. throw 和 throws 的区别?throw用来抛出异常,throws用来声明异常,提醒调用者.
  2. finally中的语句一定会执行吗?一定会.

1.2.4 异常处理的流程 (总结)

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

1.3 自定义异常

Java出了本身给出的异常类之外,我们还可以自定义异常,在重写的构造方法中,我们可以自定义异常原因.

ublic class PassWordException extends RuntimeException{//继承于运行时异常
    public PassWordException(String message) {//构造方法输入出现异常的原因
        super(message);
    }
}
public static void main(String[] args) {
        String password = "123457";
        if (password != "123456"){
            throw new PassWordException("password is false");
        }
    }

在这里插入图片描述
[注意事项]
继承自Exception时默认是编译时异常.

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

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

相关文章

Linux 内核 (十二)进程间通讯 之 消息队列

前言 这个系列的上一篇介绍了进程间通讯关于管道相关的内容及代码实例,本章要介绍关于消息队列相关的内容. 消息队列交互图示 函数原型 #include <sys/msg.h> #include <sys/ipc.h> //创建 or 打开队列 成功返回队列ID,失败返回-1 int msgget(key_t key,int fla…

探索AIGC与3D技术的融合:从图像到可探索的3D动态场景

随着人工智能和计算机图形技术的飞速发展,AIGC(人工智能生成内容)与3D技术的结合正在为我们打开一扇全新的创意之门。最近,我深入研究了几个令人兴奋的AIGC+3D方案,它们不仅展示了从单张图片或文本提示生成3D点云的强大能力,还进一步实现了AI虚拟试穿和生成高保真3D数字人…

Qt信号槽的回调机制

问&#xff1a;Qt强大的地方在哪里&#xff1f; 答&#xff1a;跨平台、信号槽。。。 问&#xff1a;信号槽是什么&#xff1f; 答&#xff1a;回调函数 问&#xff1a;怎么个回调法子 答&#xff1a;。。。 成果 信号槽本身实现过程是有些复杂的&#xff0c;所以本人参考…

CDN绕过技术

DNS域名信息收集 简介 Dns域名信息的手机&#xff0c;需要收集域名对应IP&#xff0c;域名注册人&#xff0c;DNS记录&#xff0c;子域名等一系列与域名相关的信息。 Cdn技术简介 Cdn是一个内容分发网络&#xff0c;类似于dns服务器一样&#xff0c;用户发送数据直接发送到…

AI Assistant 2024 震撼登场:AI补全功能惊艳来袭,替换GitHub Copilot Chat最友好的方式!

哈喽!欢迎来到程序视点。 前言 在之前的文章中&#xff0c;我们提到过“JetBrains 2024.1 中&#xff0c;AI Assistant 插件已被解绑&#xff0c;现在作为单独的插件在 JetBrains IDE 中可用”。 这一变化的驱动力是&#xff0c;需要在使用 AI 驱动的技术时提供更大的决策灵活…

【C语言习题】30.使用指针打印数组内容

文章目录 作业标题作业内容2.解题思路3.具体代码 作业标题 使用指针打印数组内容 作业内容 写一个函数打印arr数组的内容&#xff0c;不使用数组下标&#xff0c;使用指针。 arr是一个整形一维数组。 2.解题思路 先定义一个数组&#xff0c;使用指针打印数组内容那就是说我们…

linux驱动学习(八)之内核定制与裁剪

一、内核的配置 1) 把相关硬件平台的配置文件拷贝给.config 2) 执行make menuconfig命令 关于内核配置说明:Arrow keys navigate the menu. 方向键对菜单有效<Enter> selects submenus --->. 如果有该符号"--->",则按Enter表示进入子菜单Highlighted …

可视化图表:如此高颜值柱状图,其实简单配置就能实现。

这不又有某个boss给我图截图一些柱状性图表&#xff0c;说他们的前端觉得很难&#xff0c;说了一堆技术术语&#xff0c;他也不懂&#xff0c;截图我看到后&#xff0c;就给了他一个网址&#xff0c;马上就解决了。 在这里给大家摘录出几个比较有特色的柱状图出来&#xff0c;让…

【网络安全学习】使用Kali做渗透情报收集-01-<域名信息主机信息>

1.收集开源情报 开源情报(Open Source Intelligence&#xff0c;OSINT)是指从各种公开的渠道中寻找和获取有价值的信息 如&#xff1a;互联网、媒体、社交网络、公共数据库等开源情报具有以下特点&#xff1a; - 丰富性&#xff1a;开源情报涵盖了各种类型和领域的信息 - 可…

香橙派鲲鹏Pro(orange pi kunpeng) 开箱测试,和在娱乐功能(电视盒子),深度机器学习应用方面的测试报告

摘要 对Orange Pi kunpeng这个开发板进行综合评测&#xff0c;特别关注其作为电视盒子的性能以及在深度学习应用中的算力和稳定性。通过一个月的测试&#xff0c;我们评估了其硬件性能、软件兼容性、用户体验和实际应用潜力 引言 5月份&#xff0c;我收到了csdn 对Orange P…

论文阅读笔记:Instance-Aware Dynamic Neural Network Quantization

论文阅读笔记&#xff1a;Instance-Aware Dynamic Neural Network Quantization 1 背景2 创新点3 方法4 模块4.1 网络量化4.2 动态量化4.3 用于动态量化的位控制器4.4 优化 5 效果 论文&#xff1a;https://openaccess.thecvf.com/content/CVPR2022/papers/Liu_Instance-Aware_…

班子考核评价的重要性与实施方法

在组织管理领域&#xff0c;班子考核评价是一项至关重要的工作&#xff0c;它不仅关系到组织的发展方向和速度&#xff0c;更直接影响到组织的凝聚力和战斗力。一个科学、公正、有效的班子考核评价体系&#xff0c;能够准确反映班子的工作成效&#xff0c;激励班子成员积极作为…

前后端分离对于后端来说,是利好还是利弊呢?

前后端分离已经成为前端开发的主流模式&#xff0c;这种模式极大的解放了后端&#xff0c;让后端人员不再即当爹又当妈了&#xff0c;那么这种模式对于后端来说是利好还是利弊呢&#xff0c;如何趋利避害呢&#xff0c;贝格前端工场为大家分享一下。 一、什么前后端分离的开发…

新一代大核卷积反超ViT和ConvNet!同参数量下性能、精度、速度完胜

大核卷积网络是CNN的一种变体&#xff0c;也是深度学习领域的一种重要技术&#xff0c;它使用较大的卷积核来处理图像数据&#xff0c;以提高模型对视觉信息的理解和处理能力。 这种类型的网络能够捕捉到更多的空间信息&#xff0c;因为它的大步长和大感受野可以一次性覆盖图像…

ORB算法特征提取

声明&#xff1a;学习过程中的知识总结&#xff0c;欢迎批评指正。 ORB算法提取两路输入图像&#xff08;图像A&#xff0c;图像B&#xff09;的特征点&#xff0c;根据提取的特征点进行特征匹配得到特征对。 ​ 图像金字塔 因为在现实世界中&#xff0c;同一个物体可能会以…

leetcode-09-[232]用栈实现队列[225]用队列实现栈[20]有效的括号[1047]删除字符串中的所有相邻重复项

重点&#xff1a; 栈和队列 Java中 栈不建议用stack来实现 建议用 ArrayDeque和Linkedlist来实现 队列建议用ArrayDeque和Linkedlist来实现 两者效率比较&#xff1a; java - Why is ArrayDeque better than LinkedList - Stack Overflow 基于Linkedlist是链表等&#xff0c;除…

MySQL数据操作与查询-T5 MySQL函数

一、数学函数和控制流函数 1、数学函数 &#xff08;1&#xff09;abs(x) 计算x的绝对值。 1 select abs(‐5.5),abs(10) &#xff08;2&#xff09;pow(x,y) 计算x的y次方的值。 1 select pow(2,8),pow(8,2) &#xff08;3&#xff09;round(x) 和 round(x,y) 对数字x进…

力扣hot100:75. 颜色分类(双指针)

75.颜色分类 本题是经典的「荷兰国旗问题」&#xff0c;由计算机科学家 Edsger W. Dijkstra 首先提出。 75. 颜色分类 1、遍历两遍 遍历两遍&#xff0c;第一遍放置0的位置&#xff0c;第二遍放置1的位置&#xff0c;我们只需要维护一个当前放置位置即可。 class Solution…

数字人直播系统源码,不需要高价购买,只需这个价!

在技术领域&#xff0c;系统源码的价格往往令人咋舌&#xff0c;尤其是涉及到高端应用如数字人直播系统时。那么&#xff0c;一套数字人直播系统源码到底需要多少钱&#xff1f;面对高昂的价格&#xff0c;是否还值得进入这个行业&#xff1f; 首先&#xff0c;我们要认识到数…