Java程序基础⑪Java的异常体系和使用

目录

1. 异常的概念和分类

1.1 异常的概念

1.2 异常的分类

2. 异常的体系结构

3. 异常的处理

3.1 异常的抛出

3.2 异常的捕获与处理

3.3 异常的处理流程

4. 自定义异常类

4.1 自定义异常类的规则

4.2 自定义异常案例


1. 异常的概念和分类

1.1 异常的概念

        在Java中,异常(Exception)是指程序执行过程中可能出现的不正常情况或错误。它是一个事件,它会干扰程序的正常执行流程,并可能导致程序出现错误或崩溃。

        异常在Java中是以对象的形式表示的,这些对象是从java.lang.Throwable类或其子类派生而来。Throwable是异常类层次结构的根类,它有两个主要的子类:java.lang.Exception和java.lang.Error。

  1. Exception(异常):java.lang.Exception是表示可检查异常的基类。可检查异常是指在编译时需要显式处理的异常。Exception类及其子类用于表示程序运行过程中可能出现的外部条件、错误或其他可恢复的情况。例如,文件未找到、网络连接中断、输入格式错误等。开发人员需要通过捕获或声明这些异常来确保在程序中进行适当的异常处理。
  2. Error(错误):java.lang.Error是表示严重问题或系统级错误的基类。错误是指那些程序通常无法处理或恢复的情况,例如内存溢出、堆栈溢出、虚拟机错误等。与异常不同,错误不需要在程序中显式处理,因为它们通常表示了无法解决的问题。

        异常在Java中通过抛出(throw)和捕获(catch)的方式进行处理。当程序执行到可能引发异常的代码时,可以使用throw语句手动抛出异常对象。然后,可以使用try-catch语句块来捕获异常,并在catch块中提供相应的异常处理逻辑。在catch块中,可以根据异常的类型执行适当的操作,如日志记录、错误报告或异常处理。如果异常没有在当前方法中被捕获处理,它将继续向上级调用栈传播,直到找到合适的异常处理代码或导致程序终止。


1.2 异常的分类

在Java中,异常可以按照其类型进行分类。下面是Java中异常的主要分类:

  1. 可检查异常(Checked Exceptions):可检查异常是指在编译时会被检查的异常,程序必须显式地处理它们,否则编译器会报错。可检查异常通常表示程序在运行过程中可能出现的外部条件或错误。例如,文件不存在、网络连接问题等。可检查异常是Exception类(及其子类)的实例。
  2. 运行时异常(Runtime Exceptions):运行时异常也被称为非检查异常(Unchecked Exceptions)。这些异常在编译时不会被强制检查,而是在程序运行时才会抛出。运行时异常通常表示程序内部的错误或逻辑错误,例如,空指针引用、除以零等。运行时异常是RuntimeException类(及其子类)的实例。
  3. 错误(Errors):错误表示Java虚拟机(JVM)本身出现的严重问题,通常无法恢复或处理。错误可能是内存溢出、堆栈溢出等严重问题。与异常不同,错误一般不应该被捕获和处理,因为它们指示了无法解决的问题。错误是Error类(及其子类)的实例。

        这些异常类型的区别在于编译器对它们的检查方式以及程序员对它们的处理要求。可检查异常在编译时要求显式处理,要么通过try-catch块捕获并处理,要么通过在方法签名中声明该异常并由调用者处理。运行时异常可以选择捕获和处理,但不是强制要求。而错误通常不应该被捕获和处理。


2. 异常的体系结构

        在Java中,异常类的体系结构是通过继承关系组织的。以下是Java异常类的体系结构图及其说明:

  • Throwable是异常类体系结构的根类。它是所有异常类的超类,直接或间接地派生了Error和Exception两个主要子类。
  • Error表示严重的问题或系统级错误,它们通常是由Java虚拟机(JVM)本身引起的,例如内存溢出、堆栈溢出等。程序通常无法恢复或处理这些错误。
  • Exception是表示可检查异常的基类。它包括两个主要的分支:
  1. RuntimeException是运行时异常的基类,它表示程序内部错误或逻辑错误。这些异常通常是由编程错误引起的,例如空指针引用、除以零等。运行时异常在编译时不会被强制检查,因此可以选择捕获和处理它们,但也可以选择不处理。
  2. Exception的其他子类表示其他可检查异常,例如输入/输出异常(IOException)、SQL异常(SQLException)等。这些异常在编译时会被强制检查,程序必须显式地处理它们,否则会导致编译错误。

        Java异常类体系结构的组织方式使得开发人员可以根据异常的类型和性质来选择适当的异常类来表示和处理不同类型的异常情况。这种结构使得异常处理更加灵活和可扩展,并且提供了一致的异常处理机制。


3. 异常的处理

3.1 异常的抛出

        在Java中,异常的抛出是通过使用throw关键字来实现的。throw关键字用于抛出一个异常对象,将异常传递给调用者或上层调用栈。 以下是异常的抛出示例:

public class Example {public static void main(String[] args) {try {int result = divide(10, 0); // 调用自定义方法System.out.println("结果:" + result);} catch (ArithmeticException e) {System.out.println("发生了算术异常:" + e.getMessage());}}public static int divide(int num1, int num2) {if (num2 == 0) {throw new ArithmeticException("除数不能为零"); // 抛出算术异常}return num1 / num2;}
}

        在上面的示例中,divide()方法用于计算两个数的除法操作。如果除数为零,将会抛出一个算术异常(ArithmeticException)。在main()方法中,我们调用了divide()方法,并使用try-catch块来捕获可能抛出的异常。如果捕获到算术异常,将会输出相应的错误信息。

        另外,除了手动抛出异常,Java还提供了许多内置的异常类,例如NullPointerException、ArrayIndexOutOfBoundsException等。这些异常类可以在特定情况下自动抛出,无需显式使用throw关键字。

以下是一个示例,演示了数组越界异常的自动抛出:

public class ArrayExample {public static void main(String[] args) {int[] arr = {1, 2, 3};try {int value = arr[5]; // 数组越界,将抛出ArrayIndexOutOfBoundsException异常} catch (ArrayIndexOutOfBoundsException e) {System.out.println("发生了数组越界异常:" + e.getMessage());}}
}

        在上面的示例中,我们尝试访问数组中索引为5的元素,而实际数组只有3个元素,因此会抛出一个数组越界异常(ArrayIndexOutOfBoundsException)。通过try-catch块捕获该异常,并输出错误信息。

        异常的抛出和捕获机制使得程序能够在出现异常情况时进行适当的处理,避免程序崩溃或产生不可预测的结果。通过合理地抛出和处理异常,可以增加程序的可靠性和健壮性。


3.2 异常的捕获与处理

  • 异常声明throws

        在Java中,使用throws关键字可以在方法声明中指定该方法可能抛出的异常类型。通过使用throws关键字,方法可以将异常的处理责任委托给调用者,而不是在方法内部处理异常。 以下是异常声明throws的示例:

public class Example {public static void main(String[] args) {try {readFile("file.txt"); // 调用自定义方法} catch (FileNotFoundException e) {System.out.println("文件未找到:" + e.getMessage());}}public static void readFile(String filename) throws FileNotFoundException {// 尝试打开文件// 如果文件不存在,将抛出FileNotFoundException异常FileInputStream fis = new FileInputStream(filename);// 其他处理逻辑...}
}

        在上面的示例中,readFile()方法用于读取指定文件的内容。由于打开文件可能出现文件不存在的情况,因此在方法声明中使用了throws FileNotFoundException来指定该方法可能抛出的异常类型。这样,调用者在调用readFile()方法时,必须处理或继续向上抛出该异常。

        在main()方法中,我们调用了readFile()方法,并使用try-catch块来捕获可能抛出的FileNotFoundException异常。如果捕获到异常,将会输出相应的错误信息。

        需要注意的是,如果一个方法声明了抛出异常,但在方法内部没有实际抛出该异常,编译器会报错。因此在使用throws关键字声明异常时,需要确保方法内部的代码可能会抛出相应的异常。

        通过使用throws关键字声明异常,可将异常处理的责任从方法内部转移到调用者处,使得代码更加清晰和模块化。同时它也提供了更大的灵活性,允许在调用链中的合适位置进行异常处理。


  • try-catch捕获并处理

        在Java中,可以使用try-catch语句块来捕获和处理异常。try-catch语句块允许我们在执行可能引发异常的代码时,捕获并处理异常,从而防止程序终止或产生不可预测的结果。

以下是try-catch捕获和处理异常的示例:

public class Example {public static void main(String[] args) {try {int result = divide(10, 0); // 调用自定义方法System.out.println("结果:" + result);} catch (ArithmeticException e) {System.out.println("发生了算术异常:" + e.getMessage());}}public static int divide(int num1, int num2) {try {return num1 / num2;} catch (ArithmeticException e) {throw new ArithmeticException("除数不能为零"); // 抛出算术异常}}
}

        在上面的示例中,divide()方法用于计算两个数的除法操作。在方法内部,我们使用了try-catch语句块来捕获可能发生的算术异常。如果除数为零,将抛出一个算术异常(ArithmeticException)。在main()方法中,我们调用了divide()方法,并使用try-catch块捕获可能抛出的算术异常。如果捕获到异常,将会输出相应的错误信息。

        需要注意的是,当异常被捕获时,程序将跳转到匹配的catch块,并执行其中的代码。在catch块中,我们可以根据异常的类型执行相应的操作,例如输出错误信息、记录日志或进行其他处理逻辑。

        通过使用try-catch语句块,可以在程序中有选择地捕获和处理异常,从而保证程序的正常执行。这种异常处理机制使得代码更加健壮,能够在面对异常情况时进行适当的处理和恢复,避免程序崩溃或产生不可预测的结果。


  • finally代码块

        在Java中,finally代码块用于定义无论是否发生异常都会被执行的代码。无论是在异常被捕获和处理后,还是在异常未被捕获时,finally代码块中的代码都会被执行。finally代码块通常用于释放资源或执行必要的清理操作。

下面是使用Scanner的示例,演示了finally代码块的使用:

import java.util.Scanner;public class Example {public static void main(String[] args) {Scanner scanner = null;try {scanner = new Scanner(System.in);System.out.print("请输入一个整数: ");int num = scanner.nextInt();System.out.println("输入的整数是: " + num);} catch (Exception e) {System.out.println("发生了异常: " + e.getMessage());} finally {if (scanner != null) {scanner.close(); // 释放资源}}}
}

        在上面的示例中使用了Scanner类来读取用户的输入整数。在try块中创建了一个Scanner对象并读取用户的输入。如果在输入过程中发生异常,将会被捕获并输出相应的错误信息。

        不管是否发生异常,finally代码块中的代码都会执行。在这个示例中,在finally块中检查Scanner对象是否为空,如果不为空,则调用close()方法来释放资源。

        通过使用finally代码块,可以确保无论发生什么情况,资源都能得到正确地释放。这在需要处理资源(如文件、网络连接等)的情况下非常重要,以防止资源泄漏和程序不稳定性。

        需要注意的是,finally代码块并不是必需的,可以选择省略。但是如果使用了finally代码块,它将始终执行,无论是否发生异常。


3.3 异常的处理流程

异常的处理流程可以概括为以下几个步骤:

  1. 执行可能引发异常的代码块。这部分代码通常被包裹在try块中。
  2. 当在try块中发生异常时,程序会立即跳转到与异常类型匹配的catch块。catch块用于捕获和处理特定类型的异常。
  3. 在匹配的catch块中,根据异常的类型执行相应的操作,例如输出错误消息、记录日志或采取其他处理措施。多个catch块可以按照顺序排列,以处理不同类型的异常。
  4. 如果没有匹配的catch块或异常在catch块中未被处理,异常将被传递给上一级调用栈,继续寻找异常处理代码。
  5. 如果在当前方法中没有合适的异常处理代码,异常将继续向上层调用栈传递,直到找到能够处理异常的地方。
  6. 如果在调用栈中找到能够处理异常的catch块,相应的异常处理代码将被执行。
  7. 在异常处理完成后,程序将继续执行try-catch结构之后的代码。
  8. 如果存在finally代码块,不论异常是否发生,finally中的代码都会被执行。finally代码块通常用于释放资源、进行清理操作或确保一些必要的代码逻辑得以执行。

        通过这样的异常处理流程,可以捕获和处理异常,避免程序的意外终止,并进行适当的错误处理。异常处理使得代码具备了更好的健壮性和容错性,可以保证程序在异常情况下的正常运行,并提供相应的错误信息和处理机制。


4. 自定义异常类

4.1 自定义异常类的规则

        在Java中,可以通过创建自定义异常类来表示和处理特定的异常情况。以下是关于自定义异常类的一些规则:

  1. 自定义异常类应继承自Exception类或其子类。通常,如果自定义异常类表示非检查异常,则可以继承RuntimeException类或其子类。
  2. 自定义异常类应提供适当的构造方法。通常,至少应包含一个带有异常信息的构造方法,以便在抛出异常时传递详细信息。可以根据需要添加其他构造方法,以便传递更多的异常信息和原因。
  3. 自定义异常类可以添加自定义的方法和逻辑,以满足特定需求。例如,可以添加用于获取特定信息的方法或执行特定操作的方法。
  4. 自定义异常类的命名应具有描述性,并遵循Java的命名约定。通常,类名以Exception结尾是一种常见的命名约定,例如MyCustomException。
  5. 自定义异常类可以根据特定的异常情况进行层次化。您可以创建自定义异常类的层次结构,通过继承关系来表示不同级别或类型的异常。这有助于更好地组织和处理不同类型的异常。

以下是一个示例,展示了一个自定义异常类的规则和示例代码:

public class MyCustomException extends Exception {public MyCustomException() {super();}public MyCustomException(String message) {super(message);}public MyCustomException(String message, Throwable cause) {super(message, cause);}public MyCustomException(Throwable cause) {super(cause);}// 可以添加自定义的方法和逻辑
}

        在上述示例中,创建了一个名为MyCustomException的自定义异常类。该类继承自Exception类,并提供了多个构造方法,以便在抛出异常时传递不同的异常信息和原因。


4.2 自定义异常案例

public class Login {private String userName = "admin";private String password = "123456";public void loginInfo(String userName, String password) {try{if (!this.userName.equals(userName)) {throw new UserNameErrorException("用户名错误!");// System.out.println("用户名错误!");// return;}if (!this.password.equals(password)) {throw new PasswordException("密码错误!");// System.out.println("密码错误!");// return;}System.out.println("登陆成功");} catch (UserNameErrorException | PasswordException e){e.printStackTrace();}}public static void main(String[] args) {Login login = new Login();login.loginInfo("admin", "123456");}
}

        在上述代码中,Login类包含了一个名为loginInfo的方法,该方法接受用户名和密码作为参数。在方法中,我们使用try-catch块来捕获可能抛出的UserNameErrorExceptionPasswordException异常。

        在try块中,我们检查输入的用户名和密码是否与预定义的用户名和密码匹配。如果不匹配,我们抛出相应的异常,即UserNameErrorExceptionPasswordException。如果用户名和密码都正确,将输出"登录成功"。

        在catch块中,我们捕获并处理可能抛出的异常。通过调用printStackTrace()方法,异常的堆栈跟踪信息将被打印出来,以便进行错误排查和调试。

        在main方法中,创建一个Login对象并调用loginInfo方法来进行登录测试。在本例中,传递了正确的用户名和密码,因此输出将是"登录成功"。如果用户名或密码错误,将在控制台上打印异常的堆栈跟踪信息。

自定义异常类 PasswordException 和 UserNameErrorException :

public class PasswordException extends RuntimeException{public PasswordException(){super();}public PasswordException(String message){super(message);}
}public class UserNameErrorException extends RuntimeException{public UserNameErrorException(){super();}public UserNameErrorException(String message){super(message);}
}

        在上述代码中,PasswordExceptionUserNameErrorException类都继承自RuntimeException类,因此它们都是非检查异常。

这两个异常类提供了两个构造方法:

  1. 无参构造方法:调用父类RuntimeException的无参构造方法,用于创建一个没有特定错误信息的异常对象。
  2. 带有字符串参数的构造方法:调用父类RuntimeException的带有字符串参数的构造方法,用于创建一个带有特定错误信息的异常对象。

        通过定义这两个自定义异常类,可以在需要时抛出PasswordExceptionUserNameErrorException异常,并传递适当的错误信息。这样可以更好地处理与密码和用户名相关的异常情况,并提供有关错误的详细信息。


本篇完。

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

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

相关文章

大话特征工程:1.维数灾难与特征轮回

一、维度深渊 公元 2147 年,人类文明进入了数据驱动的超级智能时代。从金融到医疗,从教育到娱乐,所有决策都仰赖“全维计算网络”(高维特征空间)。这套系统将全球所有信息抽象成数以亿计的多维特征&#xff08…

libOnvif通过组播不能发现相机

使用libOnvif库OnvifDiscoveryClient类, auto discovery new OnvifDiscoveryClient(QUrl(“soap.udp://239.255.255.250:3702”), cb.Build()); 会有错误: end of file or no input: message transfer interrupted or timed out(30 sec max recv delay)…

JVM常见知识点

在《深入理解Java虚拟机》一书中,介绍了JVM的相关特性。 1、JVM的内存区域划分 在真实的操作系统中,对于地址空间进行了分区域的设计,由于JVM是仿照真实的机器进行设计的,那么也进行了分区域的设计。核心区域有四个,…

Windows系统Tai时长统计工具的使用体验

Windows系统Tai时长统计工具的使用体验 一、Tai介绍1.1 Tai简介1.2 安装环境要求 二、下载及安装Tai2.1 下载Tai2.2 运行Tai工具 三、Tai的使用体验3.1 系统设置3.2 时长统计3.3 分类管理 四、总结 一、Tai介绍 1.1 Tai简介 Tai是一款专为Windows系统设计的开源软件&#xff…

【架构面试】二、消息队列和MySQL和Redis

MQ MQ消息中间件 问题引出与MQ作用 常见面试问题:面试官常针对项目中使用MQ技术的候选人提问,如如何确保消息不丢失,该问题可考察候选人技术能力。MQ应用场景及作用:以京东系统下单扣减京豆为例,MQ用于交易服和京豆服…

HTML一般标签和自闭合标签介绍

在HTML中,标签用于定义网页内容的结构和样式。标签通常分为两类:一般标签(也称为成对标签或开放闭合标签)和自闭合标签(也称为空标签或自结束标签)。 以下是这两类标签的详细说明: 一、一般标…

Android GLSurfaceView 覆盖其它控件问题 (RK平台)

平台 涉及主控: RK3566 Android: 11/13 问题 在使用GLSurfaceView播放视频的过程中, 增加了一个播放控制面板, 覆盖在视频上方. 默认隐藏setVisibility(View.INVISIBLE);点击屏幕再显示出来. 然而, 在RK3566上这个简单的功能却无法正常工作. 通过缩小视频窗口可以看到, 实际…

Java Web-Tomcat Servlet

Web服务器-Tomcat Web服务器简介 Web 服务器是一种软件程序,它主要用于在网络上接收和处理客户端(如浏览器)发送的 HTTP 请求,并返回相应的网页内容或数据。以下是关于 Web 服务器的详细介绍: 功能 接收请求&#…

[Computer Vision]实验二:图像特征点提取

目录 一、实验内容 二、实验过程及结果 2.1 Harris角点检测 2.2 SIFT算法 三、实验小结 一、实验内容 采用Harris与SIFT分别提取特征点及对应的描述子,对比两者的区别(特征点数量、分布、描述子维度、图像变化对二者的影响等)利用特征匹…

【AI非常道】二零二五年一月,AI非常道

经常在社区看到一些非常有启发或者有收获的话语,但是,往往看过就成为过眼云烟,有时再想去找又找不到。索性,今年开始,看到好的言语,就记录下来,一月一发布,亦供大家参考。 有关AI非…

牛客周赛 Round 78 A-C

A.时间表查询! 链接:https://ac.nowcoder.com/acm/contest/100671/A 来源:牛客网 题目描述 今天是2025年1月25日,今年的六场牛客寒假算法基础集训营中,前两场比赛已经依次于 20250121、20250123 举行;而…

网安加·百家讲坛 | 樊山:数据安全之威胁建模

作者简介:樊山,锦联世纪教育能源工业互联网数字安全CSM(新能源运维师)课程特聘培训讲师,哈尔滨工业大学(深圳)信飞合创数据合规联合实验室特聘专家,武汉赛博网络安全人才研究中心资深专家;近24年…

java后端之登录认证

基础登录功能:根据提供的用户名和密码判断是否存在于数据库 LoginController.java RestController Slf4j public class LoginController {Autowiredprivate UserService userService;PostMapping("/login")public Result login(RequestBody User user) {…

基于SpringBoot的网上考试系统

作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏:…

Elastic Agent 对 Kafka 的新输出:数据收集和流式传输的无限可能性

作者:来 Elastic Valerio Arvizzigno, Geetha Anne 及 Jeremy Hogan 介绍 Elastic Agent 的新功能:原生输出到 Kafka。借助这一最新功能,Elastic 用户现在可以轻松地将数据路由到 Kafka 集群,从而实现数据流和处理中无与伦比的可扩…

【ROS2】RViz2界面类 VisualizationFrame 详解

1、简述 VisualizationFrame 继承自 QMainWindow 和 WindowManagerInterface; 窗口顶部是常规布局:菜单栏 和 工具栏 窗口中心是 RenderPanel,用来渲染3D画面 周围是dock区域,包括:DisplaysPanel、ViewsPanel、TimePanel、SelectionPanel 和 ToolPropertiesPanel Windo…

poi在word中打开本地文件

poi版本 5.2.0 方法1:使用XWPFFieldRun(推荐) 比如打开当前相对路径的aaaaa.docx XWPFFieldRun run paragraph.createFieldRun();CTRPr ctrPr run.getCTR().addNewRPr();CTFonts font ctrPr.addNewRFonts();// 设置字体font.setAscii(&quo…

PCIE模式配置

对于VU系列FPGA,当DMA/Bridge Subsystem for PCI Express IP配置为Bridge模式时,等同于K7系列中的AXI Memory Mapped To PCI Express IP。

【Uniapp-Vue3】request各种不同类型的参数详解

一、参数携带 我们调用该接口的时候需要传入type参数。 第一种 路径名称?参数名1参数值1&参数名2参数值2 第二种 uni.request({ url:"请求路径", data:{ 参数名:参数值 } }) 二、请求方式 常用的有get,post和put 三种,默认是get请求。…

4070s显卡部署Deepseek R1

电脑配置: 处理器:AMD 7950X 内存:32G 硬盘:致态tiplus7100 2t 显卡:4070 super 12G 部署方法: 1. 到ollama官网下载安装ollama https://ollama.com/https://ollama.com/https://ollama.com/https://…