7.0 异常处理

1. 异常概述

1.1. 异常的概念

Java中的异常是指Java程序在运行时可能出现的错误或非正常情况,比如在程序中试图打开一个根本不存在的文件,在程序中除0等。异常是否出现,通常取决于程序的输入、程序中对象的当前状态以及程序所处的运行环境。程序抛出异常之后,会对异常进行处理。异常处理将会改变程序的控制流程,出于安全性考虑,同时避免异常程序影响到其他正常程序的运行,操作系统通常将出现异常的程序强行中止,并弹出系统错误提示。

下面通过一个案例认识一下什么是异常,在本案例中,计算以0为除数的表达式,运行程序并观察程序的运行结果。

public class TestDemo {@Testpublic void test() {int result = divide(4, 0);    // 调用divide()方法,第2个参数为0System.out.println(result);}/*** 下面的方法实现了两个整数相除* @param x* @param y* @return*/public int divide(int x, int y) {int result = x / y;             //定义一个变量result记录两个数相除的结果return result;                  //将结果返回}
}

运行代码,控制台显示的运行结果如下图所示。

由上图可知,程序发生了算术异常(ArithmeticException),提示运算时出现了被0除的情况。异常发生后,程序会立即结束,无法继续向下执行。

1.2. 异常类

Java提供了大量的异常类,每一个异常类都表示一种预定义的异常,这些异常类都继承自java.lang包下的Throwable类。Throwable类的继承体系图如下所示。

由上图中可知,Throwable类是所有异常类的父类,它有两个直接子类Error类和Exception类,其中,Error类代表程序中产生的错误,Exception类代表程序中产生的异常。

(1)Error类

Error类称为错误类,它表示Java程序运行时产生的系统内部错误或资源耗尽的错误,这类错误比较严重,仅靠修改程序本身是不能恢复执行的。例如,使用java命令去运行一个不存在的类就会出现Error错误。

(2)Exception类

Exception类称为异常类,它表示程序本身可以处理的错误,在Java程序中进行的异常处理,都是针对Exception类及其子类的。在Exception类的众多子类中有一个特殊的子类—RuntimeException类,RuntimeException类及其子类用于表示运行时异常。 Exception类的其他子类都用于表示编译时异常。

(3)Throwable类的常用方法

Throwable类中的常用方法,具体如下。

方法声明

功能描述

String getMessage()

返回异常的消息字符串

String toString()

返回异常的简单信息描述

void printStackTrace()

获取异常类名和异常信息,以及异常出现在程序中的位置,把信息输出在控制台。

2. 运行时异常与编译时异常

2.1. 编译时异常

在实际开发中,经常会在程序编译时产生异常,这些异常必须要进行处理,否则程序无法正常运行,这种异常被称为编译时异常,也称为checked异常。在Exception类中,除了RuntimeException类及其子类,Exception的其他子类都是编译时异常。编译时异常的特点是Java编译器会对异常进行检查,如果出现异常就必须对异常进行处理,否则程序无法通过编译。

处理编译时期的异常有两种方式,具体如下:

  • 使用try…catch语句对异常进行捕获处理。

  • 使用throws关键字声明抛出异常,调用者对异常进行处理。

2.2. 运行时异常

另一种异常是在程序运行时产生的,这种异常即使不编写异常处理代码,依然可以通过编译,因此被称为运行时异常,也称为unchecked异常。RuntimeException类及其子类都是运行时异常。运行时异常的特点是在程序运行时由Java虚拟机自动进行捕获处理的,Java编译器不会对异常进行检查。也就是说,当程序中出现这类异常时,即使没有使用try…catch语句捕获或使用throws关键字声明抛出,程序也能编译通过,只是程序在运行过程中可能报错。

在Java中,常见的运行时异常有多种,具体如下所示。

方法声明

功能描述

ArithmeticException

算术异常

IndexOutOfBoundsException

索引越界异常

ClassCastException

类型转换异常

NullPointerException

空指针异常

NumberFormatException

数字格式化异常

运行时异常一般是由程序中的逻辑错误引起的,在程序运行时无法恢复。例如,通过数组的索引访问数组的元素时,如果索引超过了数组范围,就会发生索引越界异常,代码如下所示:

int[] arr=new int[5]; System.out.println(arr[6]);

在上面的代码中,由于数组arr的length为5,最大索引应为4,当使用arr[6]访问数组中的元素就会发生数组索引越界的异常。

2.3. 运行时异常案例

(1)算术异常

ArithmeticException,算术异常,在做整数的除法或整数求余运算时可能产生的异常,它是在除数为零时产生的异常。

public class TestDemo {@Testpublic void test() {int num = 1 / 0;}
}

(2)数组下标越界异常

ArrayIndexOutOfBoundsException,数组下标越界异常,当引用数组元素的下标超出范围时产生的异常。

public class TestDemo {@Testpublic void test() {int []num = new int[5];System.out.println(num[5]);}
}

(3)类型转换异常

public class TestDemo {@Testpublic void test() {ArrayList list = new ArrayList();list.add("1111");Integer num = (Integer) list.get(0);}
}

(4)空指针异常

NullPointerException,空指针异常,即当某个对象的引用为null时调用该对象的方法或使用对象会产生该异类。

public class TestDemo {@Testpublic void test() {String name = null;System.out.println(name.length());}
}

(5)数字格式错误异常

NumberFormatException,数字格式错误异常,在将字符串转换为数值时,如果字符串不能正确转换成数值则产生该异常。

public class TestDemo {@Testpublic void test() {Double d = Double.parseDouble("1.2m1");}
}

3. 异常处理

在Java中,通过try、catch、finally、throw、throws这5个关键字进行异常对象的处理。具体说明如下所示。

关键字

功能描述

try

里面放置可能引发异常的代码

catch

后面对应异常类型和一个代码块,该关键字表明catch块是用于处理这种类型的代码块

finally

主要用于回收在try代码块里打开的物理资源,如数据库连接、网络连接和磁盘文件。异常机制保证finally块总是被执行

throw

用于抛出一个实际的异常。它可以单独作为语句来抛出一个具体的异常对象

throws

用在方法签名中,用于声明该方法可能抛出的异常

3.1. try...catch语句

为了使发生异常后的程序代码正常执行,程序需要捕获异常并进行处理,Java提供了try…catch语句用于捕获并处理异常。try…catch语句的语法格式如下所示:

try{代码块
}catch(ExceptionType e){代码块
}

(1)try...catch语句编写注意事项

  • try代码块是必需的。

  • catch代码块和finally代码块都是可选的,但catch代码块和finally代码块至少要出现一个。

  • catch代码块可以有多个,但捕获父类异常的catch代码块必须位于捕获子类异常的catch代码块后面。

  • catch代码块必须位于try代码块之后。

(2)try...catch语句异常处理流程

由上图可知,程序通过try语句捕获可能出现的异常,如果try语句没有捕获到异常,则直接跳出try…catch语句块执行其他程序;如果在try语句中捕获到了异常,则程序会自动跳转到catch语句中找到匹配的异常类型进行相应的处理。异常处理完毕,最后执行其他程序语句。

(3)try...catch语句异常处理案例

public class TestDemo {@Testpublic void test() {try {int result = divide(4, 0);    //调用divide()方法System.out.println(result);} catch (Exception e) {                 //对异常进行处理System.out.println("捕获的异常信息为:" + e.getMessage());}System.out.println("程序继续向下执行...");}/*** 下面的方法实现了两个整数相除* @param x* @param y* @return*/public int divide(int x, int y) {int result = x / y;             //定义一个变量result记录两个数相除的结果return result;                 //将结果返回}
}

3.2. finally语句

在程序中,有时候会希望一些语句无论程序是否发生异常都要执行,这时就可以在try…catch语句后,加一个finally代码块。finally语句的语法格式如下所示:

try{代码块
} catch(ExceptionType e){代码块
}  finally{代码块
}

注意:finally代码块必须位于所有catch代码块之后。

(1)try…catch…finally语句的异常处理流程

由上图可知,在try…catch…finally语句中,不管程序是否发生异常,finally代码块中的代码都会被执行。需要注意的是,如果程序发生异常但是没有被捕获到,在执行完finally代码块中的代码之后,程序会中断执行。

(2)try…catch…finally语句的异常处理案例

public class TestDemo {@Testpublic void test() {//下面的代码定义了一个try…catch…finally语句用于捕获异常try {int result = divide(4, 0);       //调用divide()方法System.out.println(result);} catch (Exception e) {               //对捕获到的异常进行处理System.out.println("捕获的异常信息为:" + e.getMessage());return;                          //用于结束当前语句} finally {System.out.println("进入finally代码块");}System.out.println("程序继续向下…");}/*** 下面的方法实现了两个整数相除** @param x* @param y* @return*/public int divide(int x, int y) {int result = x / y;             //定义一个变量result记录两个数相除的结果return result;                  //将结果返回}
}

注意:如果在try...catch中执行了System.exit(0)语句,finally代码块不再执行。System.exit(0)表示退出当前的Java虚拟机,Java虚拟机停止了,任何代码都不能再执行了。

4. 抛出异常

方法运行过程中如果产生了异常,在这个方法中就生成一个代表该异常类的对象,并把它交给运行时系统,运行时系统寻找相应的代码来处理该异常。这个过程称为抛出异常。

4.1. throws关键字

有时方法中产生的异常不需要在该方法中处理,可能需要由该方法的调用方法处理,这时可以在声明方法时用throws子句声明抛出异常,将异常传递给调用该方法的方法处理,调用者在调用方法时,就明确地知道该方法有异常,并且必须在程序中对异常进行处理,否则编译无法通过。

使用throws关键字抛出异常的语法格式如下所示:

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

(1)使用throws关键字抛出异常案例

可以使用try…catch语句处理divide()方法抛出异常,也可以继续使用throws关键字将Exception抛出。

public class TestDemo {@Testpublic void test(){//下面的代码定义了一个try…catch语句用于捕获异常try {int result = divide(4, 2);   //调用divide()方法System.out.println(result);} catch (Exception e) {                 //对捕获到的异常进行处理e.printStackTrace();   //打印捕获的异常信息}}/*** 下面的方法实现了两个整数相除,并使用throws关键字声明抛出异常* @param x* @param y* @return* @throws Exception*/public int divide(int x, int y) throws Exception {int result = x / y;     //定义一个变量result记录两个数相除的结果return result;         //将结果返回}
}

4.2. throw关键字

在Java程序中,除了throws关键字,还可以使用throw关键字抛出异常。与throws关键字不同的是,throw关键字用于方法体内,抛出的是一个异常实例,并且每次只能抛出一个异常实例。

使用throw关键字抛出异常的语法格式如下所示:

throw ExceptionInstance;

(1)使用throw关键字抛出异常案例

public class TestDemo {@Testpublic void test(){// 下面的代码定义了一个try…catch语句用于捕获异常int age = -1;try {printAge(age);} catch (Exception e) {  // 对捕获到的异常进行处理System.out.println("捕获的异常信息为:" + e.getMessage());}}/*** 定义printAge()输出年龄* @param age* @throws Exception*/public void printAge(int age) throws Exception {if(age <= 0){// 对业务逻辑进行判断,当输入年龄为负数时抛出异常throw new Exception("输入的年龄有误,必须是正整数!");}else {System.out.println("此人年龄为:"+age);}}
}

5. 异常处理综合案例

网页前端输入学生学号、年龄、姓名信息,进行保存。输入信息需满足,学号长度为4位、年龄大于0才可以保存成功,否则提示保存失败及失败原因。

  • Student类

public class Student {private String no;private String name;private int age;public String getNo() {return no;}public void setNo(String no) {this.no = no;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Student{" +"no='" + no + '\'' +", name='" + name + '\'' +", age=" + age +'}';}
}
  • StudentController

public class StudentController {/*** 接收前端输入信息* @param student*/public void addStudent(Student student) throws Exception{StudentService service = new StudentService();service.saveStudent(student);}}

  • StudentService

public class StudentService {/*** 保存学生信息* @param student* @throws Exception*/public void saveStudent(Student student) throws Exception {//校验学号是否正确,学号为4位if(student.getNo() == null || student.getNo().length() != 4){throw new Exception("学号信息错误:" + student.getNo());}//校验学生年龄if(student.getAge() <= 0){throw new Exception("年龄信息错误:" + student.getAge());}System.out.println("保存学生信息成功,保存的学生信息是:" + student);}}
  • 测试类

public class TestDemo {/*** 模拟前端输入学生信息保存*/@Testpublic void test(){Student student = new Student();student.setNo("1001");student.setName("张三");student.setAge(20);StudentController controller = new StudentController();try{controller.addStudent(student);}catch (Exception e){System.out.println("保存学生信息失败,失败原因是:" + e.getMessage());}}}

6. Debug调试

Debug用来追踪代码的运行流程,通常在程序运行过程中出现异常,启用Debug模式可以分析定位异常发生的位置,以及在运行过程中参数的变化。

6.1. 设置断点

在左边行号栏单击左键,或者快捷键Ctrl+F8打上/取消断点,断点行的颜色可自己去设置。

6.2. 启动Debug模式

以Debug模式启动服务,左边的一个按钮则是以Run模式启动。在开发中,我一般会直接启动Debug模式,方便随时调试代码。

6.3. 调试按钮

Step Over (F8):步过,一行一行地往下走,如果这一行上有方法不会进入方法。

Step Into (F7):步入,如果当前行有方法,可以进入方法内部,一般用于进入自定义方法内,不会进入官方类库的方法,如第25行的put方法。

Step Out (Shift + F8):步出,从步入的方法内退出到方法调用处,此时方法已执行完毕,只是还没有完成赋值。

Resume Program (F9):恢复程序,比如,你在第20行和25行有两个断点,当前运行至第20行,按F9,则运行到下一个断点(即第25行),再按F9,则运行完整个流程,因为后面已经没有断点了。

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

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

相关文章

Week-T10 数据增强

文章目录 一、准备环境和数据1.环境2. 数据 二、数据增强&#xff08;增加数据集中样本的多样性&#xff09;三、将增强后的数据添加到模型中四、开始训练五、自定义增强函数六、一些增强函数 &#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f…

查看文件的二进制数据

有时候会遇到想查看一些文件的二进制的数据的需求&#xff0c;比如想看一张图片的二进制数据&#xff0c;想查看bin文件的二进制数据&#xff0c;或者想查看其它文件的二进制数据等等。 在linux和mac下有命令直接支持&#xff0c;比较方便&#xff0c;但是很多人用的是windows…

【Java 进阶篇】JavaScript JSON 语法入门:轻松理解数据的序列化和反序列化

嗨&#xff0c;亲爱的小白们&#xff01;欢迎来到这篇关于 JavaScript 中 JSON&#xff08;JavaScript Object Notation&#xff09;语法的入门指南。JSON 是一种轻量级的数据交换格式&#xff0c;广泛应用于前端开发中。通过这篇博客&#xff0c;我将带你深入了解 JSON 的语法…

[userfaultfd] 2019-BalsnCTF_KrazyNote

前言 题目不算难, 但是这代码逆向可逆死个人:) 悲悲悲 程序分析 内核版本: v5.1.9 保护: 开了 kaslr, smep, smap. 现在的题目基本都开了, 都不用看. 其中 note 模块中注册了一个 misc 设备, 其函数表中就只有 note_open 和 note_unlocked_ioctl 两个函数, 其中 note_open…

C#入门(13):特性Attribute

C# 特性&#xff08;Attributes&#xff09;是用于在运行时为程序元素&#xff08;如类、方法、属性等&#xff09;添加声明性信息的一种方式。这些信息可以在程序运行时通过反射&#xff08;Reflection&#xff09;访问。特性可以用来控制程序行为、添加元数据或者影响程序的运…

SpringBoot趣探究--1.logo是如何打印出来的

一.前言 从本篇开始&#xff0c;我将对springboot框架做一个有趣的探究&#xff0c;探究一下它的流程&#xff0c;虽然源码看不懂&#xff0c;不过我们可以一点一点慢慢深挖&#xff0c;好了&#xff0c;下面我们来看一下本篇的知识&#xff0c;这个logo是如何打印出来的&#…

数字化转型导师坚鹏:数字化时代银行网点厅堂营销5大特点分析

数字化时代银行网点厅堂营销存在以下5大特点&#xff1a; 1、产品多样化&#xff1a;在数字化时代&#xff0c;银行的产品和服务变得更加多样化。除了传统的存款、贷款、理财等金融服务外&#xff0c;还新增了各种创新产品&#xff0c;如网上银行、移动支付、投资咨询、保险、…

【开源】基于微信小程序的音乐平台

项目编号&#xff1a; S 055 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S055&#xff0c;文末获取源码。} 项目编号&#xff1a;S055&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示 四、核心代码4.1 查询单首…

开源的进销存系统都有哪些?

开源的进销存系统有很多&#xff0c;以下是其中一些比较流行的: OpenERP&#xff1a;一个集成了多个业务功能的开源ERP软件&#xff0c;可以实现进销存管理&#xff0c;会计&#xff0c;仓库管理&#xff0c;销售管理等业务功能。 Odoo&#xff1a;是OpenERP的一个分支&#x…

C语言进阶之冒泡排序

✨ 猪巴戒&#xff1a;个人主页✨ 所属专栏&#xff1a;《C语言进阶》 &#x1f388;跟着猪巴戒&#xff0c;一起学习C语言&#x1f388; 目录 前情回顾 1、回调函数 2、冒泡排序 3、库函数qsort cmp&#xff08;sqort中的比较函数&#xff0c;需要我们自定义&#xff09; …

STM32F4串口USART发送为00的解决方案

检查接线是否正确检查TX是否为复用推挽输出 3.检查是否将TX和RX引脚重映射为USART功能 在STM32中&#xff0c;每个GPIO引脚可以配置为不同的复用功能&#xff0c;例如UART、SPI、I2C等。具体来说&#xff0c;GPIO_PinAFConfig函数用于配置GPIO引脚的复用功能。它的参数包括GPIO…

2023年【四川省安全员A证】复审考试及四川省安全员A证考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 四川省安全员A证复审考试根据新四川省安全员A证考试大纲要求&#xff0c;安全生产模拟考试一点通将四川省安全员A证模拟考试试题进行汇编&#xff0c;组成一套四川省安全员A证全真模拟考试试题&#xff0c;学员可通过…

c++|引用

目录 一、引用概念 二、引用特性 三、常引用 &#xff08;具有常属性的引用变量&#xff09; 四、使用场景 一、引用概念 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&#xff0c;编译器不会为引用变量开辟内存空间&#xff0c;他和他引用的变量共用同…

Spring Cloud 简介

1、简介 Spring CloudLevel up your Java code and explore what Spring can do for you.https://spring.io/projects/spring-cloud Spring Cloud 是一系列有序框架的集合&#xff0c;其主要的设施有&#xff0c;服务发现与注册&#xff0c;配置中心&#xff0c;消息总…

计算机组成原理-主存储器与CPU的连接

文章目录 知识总览单块存储芯片与CPU的连接位扩展&#xff08;存储字的位数&#xff09;字扩展&#xff08;存储字数&#xff09;关于线选法和片选法字位同时扩展总结补充&#xff1a;译码器 知识总览 单块存储芯片与CPU的连接 数据总线&#xff0c;地址总线&#xff0c;片选线…

Postman插件如何安装(一)

我们chrome插件网热门推荐的软件之一就是postman。但是postman的适应平台分为&#xff1a;postman chrome应用程序&#xff0c;postman应用程序&#xff0c;postman插件。谷歌应用商店从2018年3月开始停止chrome应用程序的更新。除非继续使用老版本的postman chrome应用程序&am…

【代码随想录】刷题笔记Day33

前言 Day33虽说是一个月&#xff0c;但是从第一篇开始实际上已经过了8个月了&#xff0c;得抓紧啊 46. 全排列 - 力扣&#xff08;LeetCode&#xff09; 前面组合就强调过差别了&#xff0c;这道题是排序&#xff0c;因此每次要从头到尾扫&#xff0c;结合used数组 class So…

数字IC基础:有符号数和无符号数的加减运算

相关阅读 数字IC基础https://blog.csdn.net/weixin_45791458/category_12365795.html?spm1001.2014.3001.5482 首先说明&#xff0c;本篇文章并不涉及补码运算正确性的证明&#xff0c;仅是对补码运算在有符号数和无符号数中运行进行讨论。 补码运算最大的作用在于消除计算机…

机器学习8:在病马数据集上进行算法比较(ROC曲线与AUC)

ROC曲线与AUC。使用不同的迭代次数&#xff08;基模型数量&#xff09;进行 Adaboost 模型训练&#xff0c;并记录每个模型的真阳性率和假阳性率&#xff0c;并绘制每个模型对应的 ROC 曲线&#xff0c;比较模型性能&#xff0c;输出 AUC 值最高的模型的迭代次数和 ROC 曲线。 …

5 个适用于 Linux 的开源日志监控和管理工具

当Linux等操作系统运行时&#xff0c;会发生许多事件和在后台运行的进程&#xff0c;以实现系统资源的高效可靠的使用。这些事件可能发生在系统软件中&#xff0c;例如 init 或 systemd 进程或用户应用程序&#xff0c;例如 Apache、MySQL、FTP 等。 为了了解系统和不同应用程序…