[Java基本语法] 异常

🌸个人主页: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时默认是编译时异常.

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

从0到1:手动测试迈向自动化——手机web应用的自动化测试工具

引言&#xff1a; 在当今移动互联网时代&#xff0c;手机web应用已经成为人们生活中不可或缺的一部分。为了保证手机web应用的质量和稳定性&#xff0c;自动化测试工具变得十分重要。本文将介绍手机web应用自动化测试工具的选择和使用&#xff0c;提供一份超详细且规范的指南&a…

ChatGPT魔法背后的原理:如何做到词语接龙式输出?

介绍 我们都知道 ChatGPT 是 AIGC 工具&#xff0c;其实就是生成式人工智能。大家有没有想过这些问题 &#x1f914;️&#xff1a; 1、我们输入一段话&#xff0c;就可以看见它*噼里啪啦的一顿输出*&#xff0c;那么它的原理到底是什么&#xff1f; 2、到底它是怎么锁定这些…

SpringCloud之Zuul源码解析

Zuul 是在云平台上提供动态路由&#xff0c;监控&#xff0c;弹性&#xff0c;安全等边缘服务的框架。Zuul 相当于是设备和 Netflix 流应用的 Web 网站后端所有请求的前门。Zuul 可以适当的对多个 Amazon Auto Scaling Groups 进行路由请求。 其架构如下图所示&#xff1a; Zuu…

Oracle数据库安装-Linux

Oracle数据库安装-Linux 1、修改CentOS系统标志&#xff08;oracle默认不支持CentOS&#xff09;2、安装oracle 1、修改CentOS系统标志&#xff08;oracle默认不支持CentOS&#xff09; 1.1、备份原有的配置文件&#xff0c;编辑文件&#xff0c;将原有内容删除&#xff0c;替…

hrm人力管理系统源码(从招聘到薪酬的全过程人力管控系统)

一、项目介绍 一款全源码可二开&#xff0c;可基于云部署、私有部署的企业级数字化人力资源管理系统&#xff0c;涵盖了招聘、人事、考勤、绩效、社保、酬薪六大模块&#xff0c;解决了从人事招聘到酬薪计算的全周期人力资源管理&#xff0c;符合当下大中小型企业组织架构管理运…

Linux网络-HttpServer的实现

文章目录 前言一、请求报文的解析URL的解析 二、响应报文的发送Content-LenthConten-TypeCookie和Set-CookieCookie的风险 三、尝试发送一个HTML网页404网页Location 重定向 四、浏览器的多次请求行为总结 前言 之前我们简单理解了一下Http协议&#xff0c;本章我们将在LInux下…

Unity OpenCVForUnity 安装和第一个案例详解 <一>

目录 一、资源简介 二、安装使用 1.下载案例Demo 2.移动StreamingAssets文件夹 3.添加场景 三、今日案例 1.案例Texture2DToMat Example 2.什么是Mat&#xff1f; 3.如何把Texture2D变成Mat &#xff08;1&#xff09;.初始化Mat &#xff08;2&#xff09;.Cv_…

OpenAI函数调用:使用Assistants API函数工具的一个示例

Are you looking to expand GPTs capabilities? Check out this tutorial for a complete example of an AI Assistant that can send emails whenever we ask it to. 您是否希望扩展GPT的功能&#xff1f;查看这个教程&#xff0c;它提供了一个完整的示例&#xff0c;展示了…

Docker中部署Jenkins+Pipline流水线基础语法入门

场景 DockerCompose中部署Jenkins&#xff08;Docker Desktop在windows上数据卷映射&#xff09;&#xff1a; DockerCompose中部署Jenkins&#xff08;Docker Desktop在windows上数据卷映射&#xff09;-CSDN博客 DockerComposeJenkinsPipeline流水线打包SpringBoot项目(解…

AlmaLinux 8.10 x86_64 OVF (sysin) - VMware 虚拟机模板

AlmaLinux 8.10 x86_64 OVF (sysin) - VMware 虚拟机模板 AlmaLinux release 8.10 请访问原文链接&#xff1a;https://sysin.org/blog/almalinux-8-ovf/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org 2023.03.08 更新&…

EasyExcel:如何快速生成一个只含有表头的模板Excel

&#x1f341; 作者&#xff1a;知识浅谈&#xff0c;CSDN签约讲师&#xff0c;CSDN博客专家&#xff0c;华为云云享专家&#xff0c;阿里云专家博主 &#x1f4cc; 擅长领域&#xff1a;全栈工程师、爬虫、ACM算法&#xff0c;大数据&#xff0c;深度学习 &#x1f492; 公众号…

PAT B1016. 部分A+B

题目描述 正整数A的“D(为1位整数&#xff09;部分”定义为由A中所有DA组成的新整数Px。例如:给定A3862767,DA6&#xff0c;则A的“6部分”PA是66,因为A中有2个6。 现给定A、D、B、DB,请编写程序计算PAPB。 输入格式 在一行中依次输入A、DA、B、DB&#xff0c;中间以空格分隔,…

秋招突击——6/14——复习{(树形DP)树的最长路径}——新作{非递归求二叉树的深度、重复区间合并}

文章目录 引言复习树形DP——树的最长路径 新作使用dfs非递归计算二叉树的深度多个区间合并删除问题实现思路实现代码参考思路 总结 引言 这两天可能有点波动&#xff0c;但是算法题还是尽量保证复习和新作一块弄&#xff0c;数量上可能有所差别。 复习 树形DP——树的最长路…

弹幕逆向signature、a_bogus

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 本文章未经许可禁止转载&a…

qmt量化交易策略小白学习笔记第32期【qmt编程之获取行业概念数据--如何获取迅投行业成分股数据】

qmt编程之获取迅投行业成分股数据 qmt更加详细的教程方法&#xff0c;会持续慢慢梳理。 也可找寻博主的历史文章&#xff0c;搜索关键词查看解决方案 &#xff01; 感谢关注&#xff0c;咨询免费开通量化回测与获取实盘权限&#xff0c;欢迎和博主联系&#xff01; 获取迅投…

LeetCode | 387.字符串中的第一个唯一字符

这道题可以用字典解决&#xff0c;只需要2次遍历字符串&#xff0c;第一次遍历字符串&#xff0c;记录每个字符出现的次数&#xff0c;第二次返回第一个出现次数为1的字符的下标&#xff0c;若找不到则返回-1 class Solution(object):def firstUniqChar(self, s):""…

[大模型]Qwen2-7B-Instruct 接入 LangChain 搭建知识库助手

环境准备 在 autodl 平台中租赁一个 3090 等 24G 显存的显卡机器&#xff0c;如下图所示镜像选择 PyTorch–>2.1.0–>3.10(ubuntu20.04)–>12.1 接下来打开刚刚租用服务器的 JupyterLab&#xff0c;并且打开其中的终端开始环境配置、模型下载和运行 demo。 pip 换源…

2024 年最新 Python 调用 OpenAi 详细教程实现问答、图像合成、图像理解、语音合成、语音识别(详细教程)

OpenAi 环境安装 首先确保您的计算机上已经安装了 Python。您可以从 Python 官方网站下载并安装最新版本 Python。安装时&#xff0c;请确保勾选 “Add Python to PATH” &#xff08;添加环境变量&#xff09;选项&#xff0c;以便在 cmd 命令行中直接使用 Python。 安装 Op…

window上搭建open DHCP server踩坑记录

参考类似的安装说明 window10上搭建open DHCP server_opendhcpserver-CSDN博客 到安装目录里面 OpenDHCPServer.ini 这个是配置文件。 http://127.0.0.1:6789/ 是访问地址&#xff0c;这个地址只是显示结果&#xff0c;不能配置。 需要注意的是&#xff1a;必须要有一个静…

DockerHub无法访问,国内镜像拉取迂回解决方案

无法访问后&#xff0c;主要存在以下几个问题&#xff1a; 无法进行镜像的搜索无法查看镜像相关的使用说明无法直接拉取镜像 对于第二点&#xff0c;目前没啥解决思路&#xff0c;主要针对第一点和第三点。 解决无法搜索镜像 目前仅可以解决部分问题&#xff0c;在知道镜像名…