【Java进阶篇】第四章 异常处理

news2024/12/24 21:40:28

文章目录

  • 1、异常
  • 2、类Throwable
  • 3、运行时异常和编译时异常
  • 4、异常的处理
  • 5、异常导致某些代码不能被执行
  • 6、try...catch总结
  • 7、异常对象的常用方法
  • 8、try...catch和finally
  • 9、final、finally和finalize的整理区分
  • 10、如何自定义异常
  • 11、异常在实际开发中的作用
  • 12、异常与方法覆盖

在这里插入图片描述

程序执行过程中发生了不正常的情况,JVM将异常信息打印到控制台,从而方便调试和增强程序的健壮性。

1、异常

异常在Java中以类的形式存在,如NullPointerException,每一个异常类都可以创建异常对象。

NumberFormatException nfe = new NumberFormatException("数字格式化异常");

NullPointerException npe = new NullPointerException("空指针异常");

举个例子:

int a = 10;
int b = 0;
int c = a/b;
//当JVM执行到这个地方时,会new异常对象,即new ArithmeticException("/by zero");
//并且JVM将new的异常对象抛出,打印输出信息到控制台

类比于生活:

火灾是一种异常(一种抽象出来的类),而异常对象则是xxx地方发生火灾了。

2、类Throwable

父类 java.lang.Object<-------java.lang.Throwable类------>子类Error和Exception

插播:
UML,即Unified Modeling Language,统一建模语言。

用来描述类个类之间的关系,程序执行的流程,对象的状态等。

对应的工具有:Rational Rose,startUML

Throwable类

3、运行时异常和编译时异常

定义

  • 所有Exception类的直接子类,称编译时异常(并不是字面意思上的编译阶段发生的)该类异常,必须在编写程序时,预先对这种异常进行处理,不处理,则编译时抛错
  • RuntimeException及其所有的子类,称为运行时异常,该类异常在编写程序时,可处理,也可不处理

在这里插入图片描述
异常的发生就是new对象,而只有运行阶段可以new对象,故运行时异常和编译时异常都是发生在运行阶段。

两种异常的区别

  • 编译时异常发生的概率较高,又称受检异常、受控异常。类比生活中的:出门前看到外面正在下大雨,可预料,不打伞出门大概率生病,生病这个”异常“发生的概率很大,所以出门前要做”处理“拿伞。
  • 运行时异常发生的概率比较低,又称非受检异常、非受控异常。类比生活中:走在大街上,被天上掉下来的陨石砸中了,概率极低,没必要提前做出预处理。若处理,你活着就很累,相对应的,代码就很本末倒置。

4、异常的处理

处理思路1:

在调用者方法声明的位置上,使用throws关键字,抛给上一级,即谁调用,抛给谁

public class Exception1 {
    public static void main(String[] args) throws ClassNotFoundException {
        //这里main方法调用doSome方法,必须对这个异常进行预处理
        doSome();
    }

    //doSome方法的声明位置有throws ClassNotFoundException
    //这表示这个方法执过程中很有可能会出现ClassNotFoundException异常
    //ClassNotFoundException异常的直接父类是Exception,即它是编译时异常
    public static void doSome() throws ClassNotFoundException{

    }
}

在这里插入图片描述
😉
在Java中,异常发生之后如果一直上抛,最终抛给main方法,main方法继续向上抛到JVM,到JVM,程序会被终止执行。

处理思路2:

使用try……catch语句进行异常的捕捉

public class Exception1 {
    public static void main(String[] args) {
        try {
            doSome();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static void doSome() throws ClassNotFoundException{

    }
}

try{        //尝试
	m1();
}catch(FileNotFoundException e){   //e是一个引用,保存了new出来的那个异常对象的内存地址

	System.out.println("文件不存在");   //捕捉到异常以后执行的语句
}

对于运行时异常,如ArithmeticException,可以处理,也可以不处理

try{
	System.out.println(100/0);
catch(ArithmeticException e){
	System.out.println("算术异常");
}

总结:

  • throws上抛类似于推卸责任,继续吧异常传递给调用者,让调用者来决策怎么处理(继续抛还是捕捉)
  • try…catch捕捉等于把异常拦下解决了,调用者是不知道的
    异常处理图示

几点注意事项:

在这里插入图片描述

  • 在方法的定义中,+throws 异常类名,该异常类名可以是该异常类的父类,也可以是异常类名,异常类名1,异常类名2,异常类名3
  • 不建议在main方法上使用throws,因为异常若真的发生了,一定抛给JVM,则JVM会终止程序执行。而异常机制的作用和初衷就是增强程序的健壮性(即要做到异常发生了也不影响程序的执行)
  • main方法中用try…catch ,别上抛了。

5、异常导致某些代码不能被执行

异常导致某些代码块不能被执行

总结:

  • 只要异常没有被捕捉,即采用了上报的方式,则当某行代码出现异常的时候,此方法结束,方法中的后续代码不会被执行,相当于return。再往下分析,就只看其的上抛(调用者)就好。
  • try语句块中,某一行出现异常后,该行后面的代码不会执行,catch捕捉异常后,catch后的代码继续执行。

6、try…catch总结

😉 catch后,写确切的类型、写其父类型、父父类型也可以

try{
	FileInputStream fis = new FileInputStream("D:\\not_exist.java");
//这里写的是FileNotFoundException的父类IO Exception
}catch(IO Exception e){
	System.out.println("文件不存在");
}

😉 catch可以写多个,当这些异常父类一样时,直接写一个他们的父类也行,但建议精确catch,方便调试

try{
	...
//出现异常时,从上往下匹配catch
}catch(xx e){
	...
}catch(xxx e){
	...
}catch(xxxx e){
...
}

😉 catch写多个的时候,从上到下,必须遵循从小到大,若父类异常在上,则catch匹配时,父类下的精确子类一定轮不上执行,会报错。


😉 JDK8中,允许使用或"|"来连接多个异常

try{
	...
}catch(FileNotFoundException|ArithmeticException|NullPointerException e){
	...
}

上抛和捕捉如何选择?
------

如果希望调用者去处理,则用throws抛给调用者,反之,自己处理则try…catch

7、异常对象的常用方法

Exception exception = new Exception();

1)getMessage()方法

//作用:获取异常的简单描述信息
String msg = exception.getMessage();

2)printStackTrace()方法

//作用:打印异常追踪的堆栈信息
exception.printStackTrace();

举例:

public class Exception2 {
    public static void main (String[] args){
    	//异常的发生即new异常对象,那这行代码会导致程序终止运行吗?
    	//不会,这里只是new了一个异常对象,但并没有将异常对象throws抛出
    	//因此JVM会认为这是一个普通的Java对象
        NullPointerException e = new NullPointerException("发生空指针异常");
        
        String msg = e.getMessage();
        //getMessage方法的输出,其实是用有参构造方法传入的那个String
        System.out.println(msg);
        e.printStackTrace();
        System.out.println("Hello World!");
    }
}

运行结果:

多次运行可以看到,Hello World一会儿在堆栈信息之上,有时在堆栈信息之下,这是因为Java打印异常堆栈信息追踪信息的时候,采用的是异步线程的方式。

运行结果

Tip:

printStackTrace打印堆栈信息的结果也为红色,不是编译器出错了,如果是出错了,那下面的代码是不会执行的。错误分析时,从上往下看异常,下面的异常通常是上面的导致的。此外注意看包名,sun公司包后面的信息可以适当跳过。

8、try…catch和finally

  • 😉 在finally子句中的代码是最后执行的,并且一定会执行,即使try语句块中的代码出现了异常
  • 😉 finally子句必须和try一起出现
  • 😉 通常在finally语句块中完成资源的释放/关闭,以保障资源一定被关闭
    在这里插入图片描述
  • 😉 也可无catch,直接try+finally
    在这里插入图片描述
  • 😉 退出JVM时,finally语句不执行
将上面try语句块中的return;改为:

System.exit(0);
//再运行,则只输出try,finally中的语句不再执行

整理一个finally的坑,或许面试用得上:

public class Exception2 {
    public static void main (String[] args){
        int result = m();
        System.out.println(result);   //100
    }
    public static int m(){
        int i = 100;
        try{
            return i;
        }finally{
            i++;
        }
    }
}
-----
//按照刚学的执行顺序,应该是先i++,再return,但这里是特殊
//使用反编译工具可以看到m()方法其实是这样:
public static int m(){
	int i = 100;
	int j = i;
	i++;
	return j;
}

9、final、finally和finalize的整理区分

  • final是一个关键字,表示最终的,其修饰的类无法继承、修饰的方法无法覆盖、修饰的变量不能重新赋值
  • finally是一个关键字,和try一起出现,finally语句块中的代码必须执行(除非中途退出JVM)
  • finalize是Object类中的方法名(即标识符),该方法由GC机制调用

10、如何自定义异常

SUN提供的JDK内置异常不够用,实际的开发中有的异常和业务挂钩,这种异常需要我们自己定义,自定义异常的步骤是:

  • 编写一个类继承Exception(编译时异常)或者继承RuntimeException(运行时异常)
  • 提供两个构造方法,一个无参数的,一个带有String参数的
public class MyException extends Exception{
	public MyException(){
	}
	public MyException(String s){
		super(s);
	}
}

11、异常在实际开发中的作用

以下以数组模拟压栈弹栈为改良例子:

//之前的栈满是通过return+println来表达异常
public void push(Object obj){
        if(this.index >= this.elements.length-1){
            System.out.println("压栈失败,栈满");
            return;
        }
        this.index++;
        this.elements[index] = obj;
        System.out.println("压栈"+obj+"成功,栈帧指向"+ index);
    }

栈满是一种异常,我们用异常机制来改良:

/**
 * 改良后的压栈方法
 */
public void push2(Object obj) throws MyStackOperationException {
    if(index >= elements.length-1){
    	//创建异常对象,并将其抛出
        MyStackOperationException e = new MyStackOperationException("栈满");
        throw e;
        //抛出异常后,因为这个自定义异常我写的是编译时异常,故要预处理
        //这里选择throws,我定义异常的目的就是把栈满的异常信息传递出去
        //自己定义再自己捕捉,一切都没意义了,所以在方法名定义的末尾加上throws
    }
    this.index++;
    this.elements[index] = obj;
    System.out.println("压栈"+obj+"成功,栈帧指向"+ index);
}
throw new MyStackOperationException("栈满");

用这种抛异常来代替return + println

注意throw和throws的区别:

  • throws:在方法声明的位置上使用,表示上报异常信息给调用者
  • throw:手动抛出异常

12、异常与方法覆盖

覆盖那一章中提到:重写之后的方法,不能比重写之前的方法抛出更多或者更宽泛的异常,可以相等或者更少

class Animal{
    public void doSome(){
        
    }
    public void doOther() throws Exception{
        
    }
}
class Cat extends Animal{
    //抛的更多了,error
    public void doSome throws Exception{
        
    }
    //抛出更少,√
    public void doOther(){
        
    }
    //抛出一样的,√
    public void doOther2() throws Exception{
        
    }
    //抛出范围更小的,√
    public void doOther() throws NullPointerException{
        
    }
    //抛出运行时异常,√
    public void doOther() throws RuntimeException{
        
    }
}

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

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

相关文章

带联网功能的RFID宿舍门禁(六)-两年后的再次总结

文章首发及后续更新&#xff1a;https://mwhls.top/4066.html&#xff0c;无图/无目录/格式错误/更多相关请至首发页查看。 新的更新内容请到mwhls.top查看。 欢迎提出任何疑问及批评&#xff0c;非常感谢&#xff01; 带联网功能的RFID宿舍门禁 两年后又来了次总结&#xff0c…

聚观早报|中国制造成世界杯交通主力;特斯拉拟召回32万辆车

今日要闻&#xff1a;中国制造成世界杯交通主力&#xff1b;特斯拉拟召回32万辆车&#xff1b;iPhone14pro发货或延期至2023年&#xff1b;Tik Tok逆势宣布招聘&#xff1b;世界杯部署2.2万电子眼中国制造成世界杯交通主力 据消息&#xff0c;来自中国的新能源客车成了服务本届…

美国、欧洲、中国关于工业互联网的比较分析

工业革命的发展历史 1.0•机械化•大规模 2.0•电气化•自动化 3.0•信息化•产品标准 4.0•网络化•定制 3.0相当于肯德基麦当劳门店全部机械化&#xff0c;全程过程控制&#xff0c;任何一批不合格的产品&#xff0c;都可以追溯到上游任何一个环节 4.0全部设备通过中央控…

【C++笔试强训】第二十九天

&#x1f387;C笔试强训 博客主页&#xff1a;一起去看日落吗分享博主的C刷题日常&#xff0c;大家一起学习博主的能力有限&#xff0c;出现错误希望大家不吝赐教分享给大家一句我很喜欢的话&#xff1a;夜色难免微凉&#xff0c;前方必有曙光 &#x1f31e;。 &#x1f4a6;&a…

【linux】coredump问题排查

序言 记录coredump问题的一些定位技巧 1. coredump简介 coredump称为核心转储&#xff0c;就是在进程异常时的一个快照&#xff0c;保存了异常时的内存、寄存器、堆栈等数据当进程接收到某些 信号 而导致异常退出时&#xff0c;就会生成 coredump 文件core文件是ELF文件格式…

docker-compose 安装 Prometheus + Grafana 配置监控页面

安装 Prometheus Grafana docker 编排 prometheus:image: prom/prometheus:v2.40.1container_name: prometheusports:- "9090:9090"volumes:- /docker/prometheus/prometheus.yml:/etc/prometheus/prometheus.ymlnetwork_mode: "host"grafana:image: gra…

【Linux】基础:进程控制

【Linux】基础&#xff1a;进程控制 摘要&#xff1a;本文主要介绍关于Linux进程控制内容&#xff0c;分为创建、退出、等待与替换四个板块&#xff0c;希望读者可以掌握每个板块的主要概念以及使用原因和调用方法。 文章目录【Linux】基础&#xff1a;进程控制一、进程创建1.1…

Nginx重定向

Rewrite简介 Rewrite是Nginx服务器提供的一个重要基本功能&#xff0c;是Web服务器产品中几乎必备的功能。主要的作用是用来实现URL的重写。 注意:Nginx服务器的Rewrite功能的实现依赖于PCRE的支持&#xff0c;因此在编译安装Nginx服务器之前&#xff0c;需要安装PCRE库。Ngin…

(续)SSM整合之springmvc笔记(SpringMVC处理ajax请求)(P154-158)

目录 SpringMVC处理ajax请求 一 准备工作 1 新建spring_mvc_ajax com.atguigu 2 .导入依赖 3 添加web模块 4 .配置web.xml 5 . springmvc.xml 6 .创建控制层 7 . index.html 8 静态 9 部暑到tomcat上 10 启动tomcat 二 . 测试SpringMVC处理ajax 1 . ind…

TCP三次握手与四次挥手详解

TCP三次握手(建立TCP连接): 建立TCP连接&#xff0c;就是指建立一个TCP连接时&#xff0c;需要客户端和服务总共发送3个包以确认连接的建立。在socket编程中&#xff0c;这一过程由客户端执行connect来触发。 在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连…

GSN前瞻预处理

在数控加工等应用中&#xff0c;要求数控系统对机床进行平滑的控制&#xff0c;以防止较大的冲击影响零件的加工质量。 运动控制器的前瞻预处理功能可以根据用户的运动路径计算出平滑的速度规划&#xff0c;减少机床的冲击&#xff0c;从而提高加工精度。 下面用一个实例来说明…

一文了解Spring MVC(上)

目录 什么是Spring MVC 什么是MVC Spring MVC 和MVC的区别 怎么学Spring MVC Spring MVC的创建和连接 RequestMapping注解 获取参数 传递基础数据类型/包装类型&#xff08;无注解&#xff09; 添加RequestParam注解&#xff08;使用在方法参数上&#xff09; 传递自…

python——GIL锁详解

文章目录一、GIL全局解释器锁二、为什么会有GIL锁&#xff1f;三、多线程无法利用多核优势&#xff1f;计算密集型和IO密集型计算密集型——采用多进程计算密集型——采用多线程IO密集型——采用多进程IO密集型——采用多线程四、总结一、GIL全局解释器锁 1、GIL锁不是python的…

C语言 数据的存储

C语言 数据的存储一、数据与进制之间的关系1. 十进制与二进制之间的转换2. 二进制与十六进制之间的转换二、整型数据存储1. 原、反、补码2. 整型数据在内存中的存储3. 为什么整型数据存在内存中存储的是补码4. 有符号和无符号的数据类型有符号和无符号的存储范围猜想5. 关于 ch…

Java项目:SSH企业人力资源管理系统

作者主页&#xff1a;源码空间站2022 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文末获取源码 项目介绍 企业人力资源管理系统&#xff0c;分为超级管理员与普通管理员两种角色,超级管理员可以对普通管理员进行添加、删除等操作&#xff1b; 超级管理…

【k8s】1、基础概念和架构及组件

文章目录一、kubernetes概述1、什么是kubernetes&#xff1f;2、应用程序部署方式的演变3、为什么要用kubernetes&#xff1f;二、kubernetes 特性三、Kubernetes集群架构与核心组件1、master组件1.1 kube-apiserver&#xff08;中央枢纽&#xff09;1.2 kube-controller-manag…

股价下跌18%后,满帮集团(YMM)的财务业绩正在加速放缓

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 市场与竞争 根据Beroe Advantage Procuremen的一份市场研究报告&#xff0c;2020年中国道路运输服务市场的规模估计为250亿美元。 这意味着这个行业近年来的复合年增长率为6.5%。 物流参与者往往集中在中国的西南和中南部地…

.NET跨平台框架选择之一 - Avalonia UI

1. Avalonia UI简介 Avalonia UI文档教程&#xff1a;https://docs.avaloniaui.net/docs/getting-started 随着跨平台越来越流行&#xff0c;.NET支持跨平台至今也有十几年的光景了(Mono开始)。 但是目前基于.NET的跨平台&#xff0c;大多数还是在使用B/S架构的跨平台上&…

数据分析面试重点

2022年10月求职季&#xff0c;疫情的影响&#xff0c;但是也挡不住各位小伙伴&#xff0c;找工作的热情。目前&#xff0c;数据分析行业大火&#xff0c;相信很多小伙伴都想去这一行业试试水。想要成功进入数据分析行业&#xff0c;就必须得通过数据分析面试&#xff0c;面试的…

计控实验(二)——积分分离PID控制实验

太原理工大学计算机控制技术实验之积分分离PID控制实验 积分分离PID控制实验实验原理实验内容实验结果思考题实验原理 上图是一个典型的PID 闭环控制系统方框图&#xff0c;其硬件电路原理及接线图可设计如下&#xff0c;图中画“○”的线需用户在实验中自行接好&#xff0c;对…