当前位置: 首页 > news >正文

[Java基础] 异常处理机制

往期回顾

[Java基础] 流程控制

[Java基础] 运算符

[Java基础] 基本数据类型

[Java基础] Java HashMap 的数据结构和底层原理

[Java基础] 面向对象编程

目录

什么是异常处理?

异常分类

检查型异常

非检查型异常(Unchecked Exceptions)

运行时异常(RuntimeException)

错误(Error)

异常处理的主要语法

实战案例

示例代码

代码解释

处理异常的最佳实践


什么是异常处理?

Java中的异常处理是一种用于处理程序执行期间错误的机制。它允许开发者编写能够优雅地处理错误情况的健壮代码。Java的异常处理基于“抛出-捕获”模型,即当发生错误时,会创建一个表示该错误的异常对象,并将其从错误发生的地方抛出;然后,这个异常可以由专门的代码块(称为异常处理器)捕获并处理。

异常分类

检查型异常

检查型异常(Checked Exception)是指在编译时期就需要被捕获或声明的异常。这些异常是那些通常可以通过合理的编程逻辑来预防或处理的异常。如果方法可能抛出检查型异常,而调用该方法的代码没有捕获(try-catch)这个异常,或者没有在方法签名中通过throws关键字声明这个异常,编译器将报错。

以下是一些常见的检查型异常:

  • IOException:处理输入输出操作时可能抛出的异常,例如读写文件或网络通信。
  • SQLException:处理数据库操作时可能抛出的异常,例如执行SQL语句时出错。
  • ClassNotFoundException:使用Class.forName()方法动态加载类时,如果找不到指定的类,则抛出此异常。
  • InterruptedException:当一个线程在等待、睡眠或尝试执行一个阻塞操作时,另一个线程中断了当前线程,则抛出此异常。
  • ParseException:解析字符串为日期、数字等时,如果字符串格式不正确,则抛出此异常(具体实现可能因类库而异,例如java.text.ParseException)。
  • InvocationTargetException:在使用反射调用方法时,如果底层方法抛出异常,则通过此异常包装并抛出。
  • NoSuchMethodException IllegalAccessException:在使用反射访问方法或字段时,如果找不到指定的方法或没有访问权限,则抛出这些异常。
  • FileAlreadyExistsException:在创建新文件时,如果文件已经存在,则抛出此异常(具体实现可能因类库而异,例如java.nio.file.FileAlreadyExistsException)。
  • SocketException:处理网络套接字操作时可能抛出的异常,例如连接失败或套接字错误。
  • UnknownHostException:根据主机名解析IP地址时,如果无法找到主机名对应的IP地址,则抛出此异常。

非检查型异常(Unchecked Exceptions)

非检查型异常(Unchecked Exception)通常指的是RuntimeException及其子类,以及Error类及其子类。这些异常在编译时不会被强制要求处理,即可以不使用try-catch块捕获,也不需要在方法签名中通过throws关键字声明。然而,尽管编译器不强制要求处理这些异常,但在实际编程中,合理地处理这些异常仍然是非常重要的,以保证程序的健壮性和稳定性。下面会列举下常见的RuntimeExceptionError

运行时异常(RuntimeException)

  • NullPointerException
    • 当程序尝试在需要对象实例的地方使用 null 时抛出。
    • 例如:String s = null; s.length();
  • ArrayIndexOutOfBoundsException
    • 当数组索引超出其有效范围时抛出。
    • 例如:int[] array = {1, 2, 3}; int value = array[3];
  • IllegalArgumentException
    • 当传递给方法的参数不合适时抛出。
    • 例如:public void divide(int a, int b) { if (b == 0) throw new IllegalArgumentException("除数不能为零"); }
  • IllegalStateException
    • 当对象处于不适当的状态时抛出。
    • 例如:在一个尚未初始化的对象上调用某些方法。
  • ArithmeticException
    • 当发生算术错误时抛出,如除以零。
    • 例如:int result = 1 / 0;
  • ClassCastException
    • 当尝试将对象强制转换为不兼容的类型时抛出。
    • 例如:Object obj = new String("Hello"); Integer i = (Integer) obj;
  • NumberFormatException
    • 当尝试将字符串转换为数字但格式不正确时抛出。
    • 例如:int number = Integer.parseInt("abc");
  • IndexOutOfBoundsException
    • 当索引超出有效范围时抛出,类似于 ArrayIndexOutOfBoundsException,但更通用。
    • 例如:List<String> list = new ArrayList<>(); list.get(0);
  • StringIndexOutOfBoundsException
    • 当字符串索引超出有效范围时抛出。
    • 例如:String s = "hello"; char c = s.charAt(5);
  • NegativeArraySizeException
    • 当尝试创建具有负大小的数组时抛出。
    • 例如:int[] array = new int[-1];
  • UnsupportedOperationException
    • 当请求的操作不支持时抛出。
    • 例如:在不可修改的集合上尝试添加元素。
  • SecurityException
    • 当安全策略被违反时抛出。
    • 例如:尝试执行受限制的操作。
  • ConcurrentModificationException
    • 当检测到并发修改时抛出,通常发生在迭代器遍历集合时集合被修改。
    • 例如:List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c")); for (String s : list) { list.remove(s); }

错误(Error)

Error 类及其子类表示严重的系统级问题,这些问题通常表示虚拟机(JVM)本身或系统资源的问题。与异常不同,错误通常是不可恢复的,因此通常不需要在代码中捕获和处理这些错误。然而,了解常见的错误类型有助于理解程序中可能出现的问题。

以下是一些常见的 Error 类及其子类:

  • OutOfMemoryError
    • 当Java虚拟机无法分配新的对象,因为没有足够的内存可用时抛出。
    • 例如:创建一个非常大的数组或大量对象时,可能会导致此错误。
  • StackOverflowError
    • 当一个方法调用栈深度超过虚拟机限制时抛出。
    • 通常由无限递归引起。
  • NoClassDefFoundError
    • 当运行时系统试图加载一个类,但在类路径中找不到该类的定义时抛出。
    • 通常是因为类路径配置错误或依赖库缺失。
  • LinkageError
    • 表示某些链接操作失败,例如类的定义在加载时发生了不一致。
    • 子类包括 IncompatibleClassChangeErrorNoSuchFieldErrorNoSuchMethodError
  • IncompatibleClassChangeError
    • 当类的定义在加载时与其先前的定义不兼容时抛出。
    • 例如,一个接口在加载时变成了一个类。
  • NoSuchFieldError
    • 当试图访问一个不存在的字段时抛出。
    • 通常是因为类的结构在编译和运行时发生了变化。
  • NoSuchMethodError
    • 当试图调用一个不存在的方法时抛出。
    • 通常是因为类的结构在编译和运行时发生了变化。
  • AssertionError
    • 当断言失败时抛出。
    • 断言通常用于调试目的,确保某些条件在运行时为真。
  • ThreadDeath
    • 当线程被终止时抛出。
    • 通常由 Thread.stop() 方法调用引起,但不推荐使用该方法。
  • UnknownError
    • 表示一个未知的错误,通常表示JVM内部的问题。
  • VirtualMachineError
    • 表示JVM本身出现问题。
    • 子类包括 OutOfMemoryErrorStackOverflowError

异常处理的主要语法

  • try 块:用于封装可能抛出异常的代码。如果在 try 块中发生异常,则控制将转移到与之匹配的 catch 块。
  • catch 块:用于捕获 try 块中抛出的异常。每个 try 块可以有一个或多个 catch 块,用来指定可以捕获哪些类型的异常。
  • finally 块:无论是否发生异常,finally 块中的代码都会被执行。通常用于释放资源,如关闭文件或网络连接等。
  • throw 关键字:用于显式抛出一个异常对象。
  • throws 关键字:用于声明一个方法可能会抛出的异常。这可以是编译器强制要求的方法(检查型异常),也可以是可选声明的(运行时异常)。
  • 自定义异常:可以通过继承 Exception 或其子类来创建自己的异常类型。

实战案例

下面是一个完整的Java异常处理案例,它展示了如何使用trycatchfinallythrowsthrow关键字来处理异常。这个例子模拟了一个简单的文件读取操作,同时包含了一些自定义异常的处理。

示例代码

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;public class FileReadExample {public static void main(String[] args) {try {readAndProcessFile("example.txt");} catch (FileNotFoundException e) {System.err.println("文件未找到: " + e.getMessage());} catch (IOException e) {System.err.println("读取文件时发生错误: " + e.getMessage());} catch (CustomException e) {System.err.println("自定义异常: " + e.getMessage());}}public static void readAndProcessFile(String fileName) throws FileNotFoundException, IOException, CustomException {BufferedReader reader = null;try {// 尝试打开文件reader = new BufferedReader(new FileReader(fileName));String line;// 逐行读取文件内容while ((line = reader.readLine()) != null) {processLine(line);}} catch (FileNotFoundException e) {// 文件未找到时的处理throw e; // 重新抛出异常} catch (IOException e) {// 读取文件时发生其他I/O错误throw e;} catch (CustomException e) {// 处理自定义异常throw e;} finally {// 无论是否发生异常,都会执行finally块if (reader != null) {try {reader.close(); // 关闭文件流} catch (IOException e) {System.err.println("关闭文件流时发生错误: " + e.getMessage());}}}}public static void processLine(String line) throws CustomException {// 模拟处理每一行数据if (line == null || line.isEmpty()) {throw new CustomException("空行或无效行: " + line);}System.out.println("处理行: " + line);}
}//自定义异常
class CustomException extends Exception {public CustomException(String message) {super(message);}
}

代码解释

  • 导入必要的类
    • BufferedReaderFileReader 是用于文件读取的类。
    • IOException 是一个检查型异常,用于处理输入输出操作中的错误。
  • 主方法 (main 方法):
    • 调用 readAndProcessFile 方法来读取和处理文件。
    • 使用 try 块来包裹可能抛出异常的代码。
    • 捕获并处理 FileNotFoundExceptionIOExceptionCustomException
  • readAndProcessFile 方法
    • 创建一个 BufferedReader 对象,用于读取文件。
    • 使用 try 块来包裹可能抛出异常的代码。
    • 捕获并处理 FileNotFoundExceptionIOExceptionCustomException
    • 使用 throw 关键字重新抛出异常,以便在 main 方法中进一步处理。
    • 使用 finally 块来确保文件流在任何情况下都被关闭。
  • processLine 方法
    • 模拟处理每一行数据。
    • 如果行为空或无效,抛出自定义异常 CustomException
  • 自定义异常类 (CustomException):
    • 继承自 Exception 类。
    • 提供一个构造函数来设置异常消息。

处理异常的最佳实践

  • 尽量捕获具体的异常:避免捕获所有异常(如 catch (Exception e)),而应尽可能捕获具体的异常类型,这样可以更准确地处理特定错误。
  • 不要忽略异常:捕获到异常后应该做适当的处理,而不是简单地忽略它。
  • 使用 finally 块释放资源:确保无论是否发生异常,都能正确地释放资源。
  • 记录异常信息:在捕获异常后,记录异常信息可以帮助后续的问题排查。
  • 避免过度使用异常:异常处理机制虽然强大,但不应该用作常规流程控制结构。过度使用异常会影响程序性能。

http://www.mrgr.cn/news/52255.html

相关文章:

  • 测试神器~Fiddler的使用方法和操作实例
  • 那些率先在行业中推行IPD的企业命运如何?
  • java8 字符串数组验证包含关系
  • kali——fenjing的使用
  • 深度学习-26-基于PyTorch的多层感知机DNN
  • c# 前端无插件打印导出实现方式
  • RFID应急物资管理升级:智慧系统的强大优势
  • Sketch替代工具大盘点,第一款真是神仙软件!
  • C#从零开始学习(Head First C#)
  • 我谈一阶差分算子的演化
  • 什么是CRM销售漏斗?如何用CRM从0-1构建销售漏斗?
  • 【保姆级教程】DolphinScheduler本地部署与远程访问详细步骤解析
  • 【算法】C++中的二分查找
  • 竞品分析|用户体验五要素|KANO模型
  • c语言:判断素数和完数对比总结(手写代码版)
  • 安防领域的CCTV是什么?
  • 如何做好数据防泄密?九大措施帮你保护数据安全
  • 简单说说 spring 是如何处理循环依赖问题的(源码解析)
  • Java【代码 19】含有换行符\r\n的字符串匹配(源码分享)处理Word文档里的Excel表格数据
  • 博睿数据首届“观测先锋 · 2024 可观测平台创新应用案例大赛”现已启动!