Java基础43 异常(Exception)

news2025/2/23 13:10:38

异常(Exception)

  • Exception
    • 1.1 异常的概念
    • 1.2 异常体系图(☆)
    • 1.3 异常处理分类
      • 1.3.1 运行时异常(☆)
      • 1.3.2 编译时异常(☆)
    • 1.4 异常处理(☆)
      • 1.4.1 try-catch异常处理
      • 1.4.2 throws异常处理
    • 1.5 自定义异常
    • 1.6 throw和throws的对比
    • 1.7 Exception练习


Exception

1.1 异常的概念

● 什么是异常?

异常就是程序中的一些错误。

● 异常发生的原因是什么?

异常发生的原因有很多,在Java语言中,将程序执行中发生的不正常情况称为 " 异常 " 。(开发过程中的语法错误和逻辑错误不是异常

● 程序执行过程中所发生的异常事件可分为两类

1)Error(错误):Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。

比如:StackOverflowError [ 栈溢出 ] 和 OOM(out of memory),Error是严重错误,程序会崩溃。

2)Exception(异常):其他因编程错误或偶然的外在因素导致的一般性问题,是可以使用针对性的代码进行处理。

例如空指针访问,视图读取不存在的文件,网络连接中断等等。

● 异常与错误的直白理解

你写了一段代码,但是你写的代码中有语法错误,少了一些标点符号,那么运行出来的结果就会是:

java.lang.Error;

这就是错误,而不是异常。

而如果你写的那段代码没有任何语法错误,但是你写的语句是用一个数除以一个0,而在java中会因为你用0做了除数,而出现异常,并给你红色的警告:

java.lang.ArithmeticException

这就是异常


1.2 异常体系图(☆)

● 异常体系图一览

图一:

在这里插入图片描述
图二:

在这里插入图片描述

(图片来源于韩老师的视频)


1.3 异常处理分类

  1. 异常分为两大类:运行时异常和编译时异常。
  2. 运行时异常:编译器不要求强制处置的异常。 一般是指编程时的逻辑错误,是程序员应该避免其出现的异常。【java.lang.RuntimeException类及它的子类都是运行时异常】
  3. 对于运行时异常,可以不做处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响。
  4. 编译时异常:是编译器要求必须处置的异常。

1.3.1 运行时异常(☆)

● 常见的运行时异常

  1. NullPointerException (空指针异常)
  2. ArithmeticException (数学运算异常)
  3. ArrayIndexOutOfBoundsException (数组下标越界异常)
  4. ClassCastException (类型转换异常)
  5. NumberFormatException (数字格式不正确异常)

1.3.2 编译时异常(☆)

编译异常是指在编译期间,就必须处理的异常,否则代码不能通过编译。

● 常见的编译异常

  1. SQLException (操作数据库时,查询表可能发生异常)
  2. IOException (操作文件时,发生的异常)
  3. FileNotFoundException (当操作一个不存在的文件时,发生异常)
  4. ClassNotFoundException (加载类,而该类不存在时,异常)
  5. EOFException (操作文件,到文件末尾,发生异常)
  6. IllegalArguementException (参数异常)

1.4 异常处理(☆)

异常处理就是当异常发生的时候,对异常处理的方式。

● 异常处理机制

1) try - catch - finally

程序员在代码中捕获发生的异常,自行处理。

2) throws

将发生的异常抛出,交给调用者(方法)来处理,最顶级的处理者是JVM。

注意:

  1. try - catch - finally 和 throws 必须二选一
  2. 如果程序没有显示处理异常,则默认是throws

方式一 (try - catch - finally)

try{
	代码/可能的异常
}catch(Exception e){
	捕获到异常,当异常发生时,
	系统将异常封装成Exception 对象 e,
	传递给catch,得到异常对象后,程序员自行处理

	注意:如果没有发生异常,catch代码块则不执行
}finally{
	不管try代码块是否有异常发生,始终要执行finally
}

方式二 (throws)

throws是会把异常返回给上一级,直到最后的JVM,JVM会输出异常信息,然后退出程序。

在这里插入图片描述

1.4.1 try-catch异常处理

● try - catch方式处理异常介绍

Java提供try和catch块来处理异常。try块用于包含可能出错的代码。catch块用于处理try块中发生的异常。可以根据需要在程序中有多个数量的try…catch块。

try - catch 语法

try {
	可疑代码
	将异常生成对应的异常对象,传递给catch}catch(异常){
	对异常的处理
}

● try-catch 注意事项

  1. 如果异常发生了,则异常发生后面的代码不会执行,直接进入到catch块。(try块中发生异常后,try块剩下的语句不再执行)
  2. 如果异常没有发生,则顺序执行try的代码块,不会进入到catch。
  3. 如果希望不管是否发生异常,都执行某段代码(比如关闭连接,释放资源等),则使用 - finally {}
  4. 可以有多个catch语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后,子类异常在前,比如(Exception在后,NullPointerException在前),如果发生异常,只会匹配一个catch。
try{
	Person person = new Person();
	person.say();
	int i = 10/0;
} catch (NullPointerException e){
	System.out.println("here1");
	e.printStackTrace();
} catch (Exception e){
	System.out.println("here2");
	e.printStackTrace();
} finally {
	System.out.printl("here3");
}
  1. 可以进行 try - finally 配合使用,这种用法相当于没有捕获异常,因此程序会直接崩掉,应用场景:就是执行一段代码,不管是否发生异常,都必须执行某个业务逻辑。
try{
	//代码
} finally {
	//总是执行
}

1.4.2 throws异常处理

● 基本介绍

1) 如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理

2)在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。

● 使用演示

public class Throws01{
	public static void main(String[] args){
		
	}
	public void f2() throwsFileNoteFoundException	{
		//此处的FileNoteFoundException可以换成它的父类Exception
		//创建了一个文件流对象
		//1.这里的异常是一个FileNoteFoundException 编译异常
		//2.使用前面讲过的 try - catch - finally
		//3.使用throws,抛出异常,让调用f2方法的调用者(方法)处理
		//4.throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类
		//5.throws关键字也可以是异常列表,即可以抛出多个异常
		FileInputStream fis = new FileInputStream("d://aa.txt");
	}
}

● throws注意事项及其使用细节

  1. 对于编译异常,程序中必须处理,比如 try-catch 或者 throws。
  2. 对于运行时异常,程序中如果没有处理,默认就是throws的方式处理。
  3. 子类重写父类的方法时,对抛出异常的规定:子类重写的方法,所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常的类型的子类型。
  4. 在throws过程中,如果有方法 try - catch,就相当于处理异常,就可以不必throws。

注意!!!

● 第一点

下面的代码,在f1()中调用 f3(),如果我解开f3的注释,就会出现红色的警告,原因是:

f3()抛出的是一个编译异常,即这时,就要f1()必须处理这个编译异常。

public static void f1(){
	//f3();
}

public static void f3() throws FileNotFoundException{
	FileInputStream fis = new FileInputStream("d://aa.txt");
}

处理方法

在f1()中,要么 try - catch - finally,或者继续throws这个编译异常

选用throws方法处理

public static void f1() throws FileNotFoundException{
	f3();
}

public static void f3() throws FileNotFoundException{
	FileInputStream fis = new FileInputStream("d://aa.txt");
}

● 第二点

下面的代码中在f4()中调用f5()并没有报错,原因是:

f5()抛出的是运行异常,而Java中,并不要求程序员显示处理运行异常,因为有默认处理机制。

public static void f4(){
	f5();
}

public static void f5() throws AritmeticeException{
}

1.5 自定义异常

● 什么是自定义异常?

当程序中出现了某些 “错误” ,但该错误信息并没有在Throwable子类中描述处理,这个时候就可以自己设计异常类,用于描述该错误信息。

● 自定义异常的步骤

  1. 定义类:自定义异常类名(程序员自定)继承Exception 或 RuntimeException。
  2. 如果继承Exception,则属于编译异常
  3. 如果继承RuntimeException,则属于运行异常(一般来说都是继承RuntimeException)

● 自定义异常的应用实例

实例1

当我们接收Person对象年龄时,要求范围在18 - 120 之间,否则就抛出一个自定义异常(要求
继承RuntimeException),并给出提示信息。

代码实现

public class Test02 {
    public static void main(String[] args) {
        int age = 23;
        //要求范围在18 - 120 之间,否则就抛出一个自定义异常
        if(!(age >=18 && age <= 120)){
            //通过构造器设置年龄
            throw new ageException("年龄要求在18—120之间。");
        }
        System.out.println("输入的年龄范围正确。");
    }

    //自定义异常类
    static class ageException  extends RuntimeException{
        public ageException(String message) { //构造器
            super(message);
        }
    }
}

注意:

一般情况下,我们自定义异常是继承RuntimeException,即把自定义异常做成运行时异常,好处是:我们可以使用默认的处理机制,比较方便。


1.6 throw和throws的对比

意义位置后面跟的内容
throws异常处理的一种方式方法声明处异常类型
throw手动生成异常对象的关键字方法体中异常对象

throw使用实例

看下面的测试代码中输出什么内容?

ReturnExceptionDemo类

class ReturnExceptionDemo{
	static void methodA(){
		try{
			System.out.println("进入方法A");	
			throw new RuntimeException("制造异常");
		}finally{
			System.out.println("用A方法的finally");
		}
	}
	static void methodB(){
		try{
			System.out.println("进入方法B");
			return;	
		}finally{
			System.out.println("调用B方法的finally");	
		}
	}
}

main方法

public static void main(String[] args){
	try{
		ReturnExceptionDemo.methodA();
	}catch(Exception e){
		System.out.println(e.getMessage());
	}
		ReturnExceptionDemo.methodB();
}

答案

在这里插入图片描述

1.7 Exception练习

看看下面代码是否正确,为什么?

题一:

String friends[] = {"tom","jack","milan"};
for(int i = 0; i < 4; i++){
	System.out.println(friends[i]);
}

题二:

Cat c = new Cat();
cat = null;
System.out.println(cat.name);

题三:

public class AAA{
	int x;
	public static void main(){
		int y;
		AAA a = new AAA();
		y = 3 / a.x;
		System.out.println("program ends ok!");
	}
}

题四:

class Person{
	public static void main(String[] args){
		Object obj = new Date();
		Person person;
		person = (Person)obj;
		System.out.println(person);
	}
}

答案

题一:

ArrayIndexOutOfBoundsException (数组越界异常)

题二:

NullPointerException(空指针异常)

题三:

ArithmeticException (数学运算异常)

题四:

ClassCastException (类型转换异常)


● try - catch 异常处理练习

题一

以下代码输出什么?

public class Exception01{
	public static int method(){
		try{
			String[] names = new String[3];
			if(names[1].equals("tom")){
				System.out.println(names[1]);
			}else{
				names[3] = "coco";	
			}
			return 1;
		} catch (ArrayIndexOutOfBoundsException e){
			return 2;
		} catch (NullPointerException e){
			return 3;
		} finally {
			return 4;	
		}
	}
	public static void main(String[] args){
		System.out.println(method());
	}
}

分析

  1. 创建数组后并没有给数组添加值,所以数组所存的三个数据都为Null。
  2. 进入到if语句里,names[1]的值为Null,所以会有NullPointerException异常的错误信息报出。
  3. 当获取到NullPointerException时会进入return3的catch中。
  4. 但是注意:try - catch 的结构最后有一个finally,所以即使你捕获到了NullPointerException也必须要执行finally,所以最后的结果是return 4,输出的结果为:4。

结果

4


题二

public class Exception02{
	public static int method(){
		int i =1;
		try{
			i++;
			String[] names = new String[3];
			if(names[1].equals("tom")){
				System.out.println(names[1]);
			}else{
				names[3] = "coco";	
			}
			return 1;
		} catch (ArrayIndexOutOfBoundsException e){
			return 2;
		} catch (NullPointerException e){
			return ++i;
		} finally {
			return ++i;	
		}
	}
	public static void main(String[] args){
		System.out.println(method());
	}
}

分析

  1. int i = 1;
  2. 进入到try,i++(i=2),创建了数组后,并没有给数组赋值,所以数组依旧是三个Null。
  3. 进入到if,由于数组里是null,所以程序会报空指针异(NullPointerException)。
  4. 进入到catch里,传入NullPointerException e,由于有finally,所以return 不执行,但是 i 是先自增才输出,所以i就先变为了3,才继续下一步。
  5. 执行finally里的代码,return ++i;最后输出的结果为4。

答案

在这里插入图片描述


题三

public class Exception02{
	public static int method(){
		int i =1;
		try{
			i++;
			String[] names = new String[3];
			if(names[1].equals("tom")){
				System.out.println(names[1]);
			}else{
				names[3] = "coco";	
			}
			return 1;
		} catch (ArrayIndexOutOfBoundsException e){
			return 2;
		} catch (NullPointerException e){
			return ++i;
		} finally {
			++i;
			System.out.println("i="+ i);	
		}
	}
	public static void main(String[] args){
		System.out.println(method());
	}
}

分析

  1. i=1,程序进入try中,i++(i=2),由于创建数组时并没有给出数组的值,所以数组里3个位置都为Null。
  2. 进入if,由于三个位置的值都是Null,所以程序出现NullPointerException异常,进入到catch中。
  3. 进入到NullPointerException e 的catch中,++i(i=3),这里的 i 由一个临时变量temp存储起来,再进入到finally。
  4. 进入到finally中,++i(i=4),打印出:“i=4”,由于finally中只有输出语句,程序并没有结束,所以还会回到上一级的catch里。
  5. 回到NullPointerException的catch中,执行return ++i;(return temp)输出结果3。
  6. 所以最终得结果为:i=4,3。

答案

**答案**


● 本章练习

题一

  1. 编写应用程序EcmDef.java,接收命令行的两个参数(整数),计算两数相除。
  2. 计算两个数相除,要求使用方法cal(int n1,int n2)
  3. 对数据格式不正确(NumberformatException)、缺少命令行参数(ArrayIndexOutOfBoundsException)、除0进行异常处理(ArithmeticException)。

代码实现

public class Homework01{
	public static void main(String[] args){
		try{
			//验证输入的参数的个数是否正确(两个参数)
			if(args.length != 2){
				throw new ArrayIndexOutOfBoundsException("参数个数不对");	
			}
			//接收整数
			int n1 = Integer.parseInt(args[0]);
			int n2 = Integer.parseInt(args[1]);
			
			//该方法可能抛出ArithmeticException
			double res = cal(n1,n2); 
			System.out.println("计算结果是=" + res);
			
		} catch(ArrayIndexOutOfBoundsException e){
			System.out.println(e.getMessage());	
		} catch(NumberFormatException e){
			System.out.println("参数格式不正确,需输出整数");
		} catch(ArithmeticException e){
			System.out.println("出现了除0的异常");
		}
	}
	
	//cal方法,求两数商
	public static double cal(int n1,int n2){
		return n1/n2;
	}
}

题二

看看以下代码是否会发生异常,如果会,是哪种异常?如果不会,则打印结果是什么?

public static void main(String[] args){
	if(args[4].equals("jock")){ 
		System.out.println("AA");
	}else{
		System.out.println("BB");
	}
	Object o = args[2]; 
	Integer i = (Integer)o;
}

分析与答案

这里的args.length=0,因为没有给args一个值或者长度,所以会发生ArrayIndexOutOfBoundsException(数组越界异常)

if(args[4].equals("jock"))

String -> Object,发生了向上转型,所以不会异常

Object o = args[2]; 

这里会发生异常(ClassCastException),转型错误。

Integer i = (Integer)o;

题三

写出程序结果

public static void func(){
	try{
		throw new RuntimeException();
	}
	finally{
		System.out.println("B");
	}
}
public static void main(String[] args){
	try{
		func();
		System.out.println("A");
	} catch (Exception e){
		System.out.println("C");
	}
	System.out.println("D");
 }
}

答案

在这里插入图片描述


题四

写出程序结果

public static void main(){
	try{
		showExce();
		System.out.println("A");
	} catch(Exception e){
		System.out.println("B");
	} finally{
		System.out.println("C");
	}
	System.out.println("D");
}
public static void showExce() throws Exception{
	throw new Exception();
}

答案
在这里插入图片描述

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

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

相关文章

关于联想Y7000P睡眠后无法唤醒问题修复

这个新的机器是WINDOWS11的&#xff0c;症状了自己睡眠后就醒不过来了&#xff0c;于是我找到了公众号&#xff0c;提示下载一个软件修复驱动&#xff0c;http://tools.lenovo.com.cn/tools/exeTools/download?tool_id233但是执行后还是发现有问题&#xff0c;而且比较诡异于是…

【C++】秋招实习面经汇总篇

C面经汇总 系列综述&#xff1a; 目的&#xff1a;本系列是个人整理为了秋招和实习面试的&#xff0c;整理期间苛求每个知识点&#xff0c;平衡背诵量与深入程度。 来源&#xff1a;材料主要源于阿秀的笔记和《王道考研复习指导》进行的&#xff0c;每个知识点的修正和深入主要…

MySQL索引篇

文章目录说明&#xff1a;索引篇一、索引常见面试题按数据结构按物理存储分类按字段特性分类按字段个数分类索引缺点&#xff1a;什么时候适用索引&#xff1f;什么时候不需要创建索引&#xff1f;常见优化索引的方法&#xff1a;发生索引失效的情况&#xff1a;二、从数据页角…

C#把图片放到picturebox上的指定位置,PointToClient与PointToScreen解读

1、C#中如何把图片放到picturebox上的指定位置 构造一个跟picturebox1一样大小的Bitmap&#xff0c; 设置给picturebox1&#xff0c; 然后在上面画图 Bitmap image new Bitmap(picturebox1.Size.Width, picturebox1.Size.Height); Graphics device Graphics.FromImage(imag…

FPGA电源电流参数

一、FPGA里各个电源释义 VCCINT VCCINT是FPGA芯片的内核电压&#xff0c;是用来给FPGA内部的逻辑门和触发器上的电压。即芯片的晶体管开关是有核心电压提供。当内部逻辑工作时钟速率越高&#xff0c;使用逻辑资源越多&#xff0c;则核心电压供电电流会更大&#xff0c;可高达几…

【halcon】模板匹配和仿射变换总结

前言 模板匹配和仿射变换&#xff0c;经常一起使用&#xff0c;他们之前的位置变换一般有两种情况&#xff01; 情况一 模板是一个很正的图&#xff0c;利用模板的位置&#xff0c;将歪的图像摆正。 情况二 模板和图片正不正都无所谓&#xff0c;只需想模板的位置&#xff0…

内网穿透/组网/设备上云平台EasyNTS上云网关的安装操作指南

EasyNTS上云网关的主要作用是解决异地视频共享/组网/上云的需求&#xff0c;网页对域名进行添加映射时&#xff0c;添加成功后会生成一个外网访问地址&#xff0c;在浏览器中输入外网访问地址&#xff0c;即可查看内网应用。无需开放端口&#xff0c;EasyNTS上云网关平台会向Ea…

进程间同步

并发 线程和进程都是一个调度的单位 并发进程之间的关系 交互关系之间的关系是很复杂的&#xff0c;假如一个进程需要等待另外一个进程的调用才可以运行&#xff0c;就如下面这个例子 竞争关系 上面这个区叫做临界区域 协作方式 前面我们说过异步和同步的概念 那么异…

算法笔记(十一)—— 并查集、KMP

并查集 支持集合快速合并 所有数据生成各自的集合&#xff0c;需要提供查询两个两素是不是属于一个集合&#xff0c;和集合合并操作&#xff0c;并查集能够在常数时间级别上对两个操作进行实现 1. 构造结构&#xff08;数据指针&#xff09;&#xff0c;将自己的指针指向自己…

激光雷达介绍

全球汽车行业正在进行自动化变革&#xff0c;这将彻底改变交通运输的安全和效率水平。戴姆勒在S级豪华车型中引入L3级自动驾驶&#xff08;L3&#xff0c;在特定条件下自动驾驶&#xff0c;人类驾驶员一旦被请求就会随时接管&#xff09;是自动驾驶革命的一个重大突破。其他多家…

浅谈SQL中的union和union all

文章目录概念基础语法使用技巧区别总结概念 MySQL UNION 操作符用于连接两个以上的 SELECT 语句的结果组合到一个结果集合中。多个 SELECT 语句会删除重复的数据。 UNION 操作符选取不同的值&#xff0c;如果允许得到重复的值&#xff0c;可以使用 UNION ALL 基础语法 -- u…

基于Spring Boot+Vue的在线考试系统(有错题训练功能)

文章目录项目介绍主要功能截图&#xff1a;登录系统日志在线考试错题训练考试记录题库管理试题管理角色管理用户管理部分代码展示设计总结项目获取方式&#x1f345; 作者主页&#xff1a;Java韩立 &#x1f345; 简介&#xff1a;Java领域优质创作者&#x1f3c6;、 简历模板、…

解决:文档根元素 “configuration“ 必须匹配 DOCTYPE 根 “null“或者“mapper” 必须匹配 DOCTYPE 根 “null”

文档根元素 "configuration" 必须匹配 DOCTYPE 根 "null 出现的原因是在配置mybatis-config.xml的时候没有把文件中的配置信息加进去导致的 解决的方式只需要在<configuration>标签前面加上如下内容: <?xml version"1.0" encoding"UT…

MySQL —— 库的操作

文章目录1. 创建数据库2. 字符集和校验规则3. 数据库的基本操作3.1 查看数据库3.2 显示创建数据库的语句3.3 修改数据库3.4 删除数据库3.5 备份&#xff0c;还原数据库4. 查看数据库的连接情况1. 创建数据库 基本语法&#xff1a; create database if not exists 数据库名 选项…

共享内存

简介&#xff1a; 共享内存两个或多个进程共享物理内存的同一块区域&#xff08;通常被称为段&#xff09;&#xff0c;由于一个共享内存段会称为一个进程用户空间的一部分&#xff0c;因此这种IPC机制无需内核介入。需要做的就是让一个进程将数据复制到共享内存段中&#xff…

数据挖掘,计算机网络、操作系统刷题笔记51

数据挖掘&#xff0c;计算机网络、操作系统刷题笔记51 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学生都得去找开发&#xff0c;测开 测开的话&#xff0c;你就得学数据库&#xff0c;sql&#xff0c;orac…

剑指 Offer 32 - I. 从上到下打印二叉树

摘要 剑指 Offer 32 - I. 从上到下打印二叉树 剑指 Offer 32 - II. 从上到下打印二叉树 II 剑指 Offer 32 - III. 从上到下打印二叉树 III 一、二叉树的层序遍历 题目要求的二叉树的从上至下打印&#xff08;即按层打印&#xff09;&#xff0c;又称为二叉树的广度优先搜索…

解决问题:resource IDS cannot be used in a switch statement in Android library

# 发现问题在抽取lib的时候发现了这样一个问题&#xff0c;如图所示&#xff1a;1. 很正常的onClick事件的处理&#xff0c;使用的swtich语句&#xff0c;但是却报了resource IDS cannot be used in a switch statement in Android library这个问题&#xff0c;原因是...2. and…

kafka架构体系

Kafka简介 Kafka是一个由Scala和Java编写的企业级的消息发布和订阅系统&#xff0c;最早是由Linkedin公司开发&#xff0c;最终开源到Apache软件基金会的项目。Kafka是一个分布式的&#xff0c;支持分区的&#xff0c;多副本的和多订阅者的高吞吐量的消息系统&#xff0c;被广…

【单目标优化算法】樽海鞘群算法(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…