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

Java异常处理全解析:从基础到自定义

目录

  • 🚀前言
  • 🤔异常的定义与分类
    • 💯运行时异常
    • 💯编译时异常
    • 💯异常的基本处理
  • 🌟异常的作用
  • 🐧自定义异常
    • 💯自定义运行时异常
    • 💯自定义编译时异常
  • ✍️异常的处理方案
    • 💯方案一:异常捕获与用户友好提示
    • 💯方案二:异常捕获与自动修复

🚀前言

在这里插入图片描述

大家好!我是 EnigmaCoder
本文介绍java的异常部分,从基础到自定义,最后到处理方案进行全解析。

🤔异常的定义与分类

定义Java 中的异常是程序运行时发生的错误或意外情况,是Throwable类的子类,用于封装程序执行过程中出现的不正常事件,可通过异常处理机制进行捕获和处理,分为可处理的Exception(包括受检查异常和运行时异常)和不可处理的Error(系统级错误)。

异常的分类

Java 异常体系基于Throwable类,主要分为两大类:

  • Error:系统级错误(如内存溢出OutOfMemoryError),程序无法处理,也就是说系统一旦出现问题,sun公司会把这些问题封装成Error对象给出来。
  • Exception:指可被程序捕获和处理的异常,我们程序员通常会用Exception以及它的孩子来封装程序出现的问题,其进一步分为:
    • 运行时异常(RuntimeException):RuntimeException及其子类,编译阶段不会出现错误提示,运行时出现的异常。(如:数组索引越界异常)
    • 编译时异常(Checked Exception):编译阶段会出现错误提示。(如:日期解析异常)

💯运行时异常

特点:编译阶段不会报错,运行时出现的异常,继承自RuntimeException类。

示例:

public class Text {public static void main(String[] args) {int []arr={1,2,3,4,5};System.out.println(arr[5]);}
}

这是一段数组越界的的代码,编译时没有报错,运行时就会出现以下报错:

在这里插入图片描述

💯编译时异常

public class Text {public static void main(String[] args) {show();}public static void show(){System.out.println("==程序开始==");String str="2025-01-01 00:00:00";SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Date date=sdf.parse(str);System.out.println(date);System.out.println("==程序结束==");}
}

报错信息如下:
在这里插入图片描述
在这里插入图片描述

💯异常的基本处理

  • 抛出异常(throws

    在方法上使用throws关键字,可以将方法内部出现的异常抛出去给调用者处理。

格式如下:

方法  throws 异常1,异常2,异常3 ...{...
}
  • 捕获异常(try...catch

    直接捕获程序出现的异常。

格式如下:

try{//监视可能出现异常的代码
}catch (异常类型1 变量){//处理异常
}catch (异常类型2 变量){//处理异常
}...

🌟异常的作用

  • 作用1:异常是用来定位程序bug的关键信息

异常是程序运行过程中发生错误或异常情况时抛出的信号。它包含了丰富的调试信息,可以帮助开发者快速定位和修复问题。具体来说:

  1. 异常类型:指明错误的性质,如NullPointerExceptionArrayIndexOutOfBoundsException等。
  2. 异常信息:描述错误的具体原因,如"Index 5 out of bounds for length 3"。
  3. 堆栈跟踪:显示异常发生时的调用链,帮助定位问题发生的具体位置。
try {int[] arr = new int[3];System.out.println(arr[5]);
} catch (ArrayIndexOutOfBoundsException e) {e.printStackTrace();// 输出:// java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 3//     at Main.main(Main.java:5)
}

通过分析异常信息,开发者可以快速定位到数组越界的问题发生在Main.java文件的第5行。

  • 作用2:可以作为方法内部的一种特殊返回值以便通知上层调用者,方法的执行问题

在方法设计中,异常机制提供了一种优雅的错误处理方式,相比传统的错误码返回具有以下优势:

  1. 强制处理:调用者必须处理或继续抛出检查型异常(Checked Exception)。
  2. 信息丰富:可以携带详细的错误描述和上下文信息。
  3. 代码解耦:将正常业务逻辑与错误处理逻辑分离,提高代码可读性。

应用场景示例:

public void transfer(Account from, Account to, double amount) throws InsufficientBalanceException {if (from.getBalance() < amount) {throw new InsufficientBalanceException("账户余额不足,当前余额:" + from.getBalance());}// 执行转账逻辑
}// 调用方法
try {transfer(accountA, accountB, 1000);
} catch (InsufficientBalanceException e) {System.out.println("转账失败:" + e.getMessage());// 输出:转账失败:账户余额不足,当前余额:500.0
}

通过抛出异常,transfer方法清晰地表达了业务约束,调用方可以针对性地处理特定错误情况,而不是依赖模糊的错误码或布尔返回值。

🐧自定义异常

java无法为这个世界上全部的问题都提供异常类来代表,如果企业自己的某种问题,想通过异常来表示,以便用异常来管理该问题,那就需要自己来定义异常类了。

💯自定义运行时异常

  • 定义一个异常类继承RuntimeException
public class CustomRuntimeException extends RuntimeException {// 类体
}
  • 重写构造器
public class CustomRuntimeException extends RuntimeException {// 无参构造器public CustomRuntimeException() {super();}// 带消息的构造器public CustomRuntimeException(String message) {super(message);}// 带消息和原因的构造器public CustomRuntimeException(String message, Throwable cause) {super(message, cause);}// 带原因的构造器public CustomRuntimeException(Throwable cause) {super(cause);}
}
  • 通过throw new 异常类(xxx)来创建异常对象并抛出。
public void someMethod(int value) {if (value < 0) {throw new CustomRuntimeException("Value cannot be negative");}// 其他逻辑
}

特点:编译阶段不报错,运行时才可能出现。

💯自定义编译时异常

  • 定义一个异常类继承Exception
public class CustomCompileException extends Exception {// 异常类的具体实现
}
  • 重写构造器。
public class CustomCompileException extends Exception {// 无参构造器public CustomCompileException() {super();}// 带有错误信息的构造器public CustomCompileException(String message) {super(message);}// 带有错误信息和原因的构造器public CustomCompileException(String message, Throwable cause) {super(message, cause);}// 仅带有原因的构造器public CustomCompileException(Throwable cause) {super(cause);}
}
  • 通过throw new 异常类(xxx)创建异常对象并抛出。
public void validateInput(String input) throws CustomCompileException {if (input == null || input.isEmpty()) {throw new CustomCompileException("输入不能为空");}// 其他逻辑
}

特点:编译阶段就报错,提醒十分激进。

✍️异常的处理方案

💯方案一:异常捕获与用户友好提示

底层异常层层往上抛出,最外层捕获异常,记录下异常信息,并响应适合用户观看的信息进行提示。

处理流程

  • 异常抛出:在底层代码中,当检测到异常情况时,使用 throw 关键字抛出异常对象。例如,在数据库操作中,如果查询失败,可以抛出 SQLException

  • 异常传递:异常会沿着调用栈向上传递,直到被捕获。中间层代码可以选择不处理异常,继续向上抛出。例如,在服务层捕获SQLException 后,可以将其包装为自定义的业务异常 BusinessException 并继续抛出。

  • 最外层捕获:在应用的最外层(如控制器层或主函数)使用 try-catch块捕获所有异常。例如,在 Spring MVC的控制器中,可以使用 @ExceptionHandler 注解来统一处理异常。

  • 记录日志:捕获异常后,使用日志框架(如 Log4jSLF4J)记录异常的详细信息,包括异常类型、堆栈轨迹、发生时间等。这有助于后续的问题排查和分析。

  • 用户提示:根据异常类型,生成适合用户观看的提示信息。例如,对于网络超时异常,可以提示“网络连接不稳定,请稍后重试”;对于权限不足异常,可以提示“您没有权限执行此操作”。

示例代码

try {// 业务逻辑代码
} catch (BusinessException e) {logger.error("业务异常: ", e);return new Response("操作失败,请检查输入是否正确");
} catch (Exception e) {logger.error("系统异常: ", e);return new Response("系统繁忙,请稍后重试");
}

应用场景

  • Web 应用中的全局异常处理
  • 微服务架构中的服务间调用异常处理
  • 桌面应用程序中的用户操作异常处理

💯方案二:异常捕获与自动修复

最外层捕获异常后,尝试重新修复。

处理流程

  • 异常捕获:在最外层代码中捕获异常,与方案一类似。

  • 异常分析:根据异常类型和上下文信息,判断是否可以进行自动修复。例如,对于网络连接异常,可以尝试重新连接;对于文件读取异常,可以尝试从备份文件读取。

  • 修复尝试:

    • 重试机制:对于暂时性异常(如网络抖动),可以设置重试次数和间隔时间,多次尝试执行操作。
    • 备用方案:对于无法直接修复的异常,可以切换到备用方案。例如,主数据库不可用时,切换到备用数据库。
    • 资源清理:在修复过程中,可能需要释放已占用的资源,如关闭文件句柄、释放数据库连接等。
  • 结果处理:

    • 如果修复成功,继续正常执行后续逻辑。
    • 如果修复失败,记录日志并按照方案一的方式向用户提示错误信息。

示例代码

int retryCount = 3;
while (retryCount > 0) {try {// 可能失败的操作performOperation();break; // 成功则退出循环} catch (NetworkException e) {retryCount--;if (retryCount == 0) {logger.error("网络连接失败,重试次数用尽");return new Response("网络连接失败,请检查网络设置");}Thread.sleep(1000); // 等待1秒后重试}
}

应用场景

  • 分布式系统中的容错处理
  • 实时数据处理系统的故障恢复
  • 自动化运维系统中的错误自愈

注意事项

  • 自动修复可能会掩盖潜在的系统问题,应谨慎使用
  • 需要设置合理的重试次数和间隔时间,避免无限重试
  • 对于关键业务操作,建议在自动修复后仍进行人工确认

通过以上两种方案,可以有效地处理系统中的异常情况,提高系统的稳定性和用户体验。具体选择哪种方案,需要根据业务场景和异常类型来决定。

相关文章:

  • 【Linux】C语言模拟实现shell命令行(程序替换原理)
  • Web渗透红队实战:企业级对抗的工程化突破手册
  • C++类与对象(二):六个默认构造函数(二)
  • Spark大数据分与实践笔记(第五章 HBase分布式数据库-02)
  • Python MD5加密算法脚本
  • 深入浅出IIC协议 - 从总线原理到FPGA实战开发 --第四篇:I2C工业级优化实践
  • vue调后台接口
  • 现代化SQLite的构建之旅——解析开源项目Limbo
  • 基于STM32的智能台灯_自动亮度_久坐提醒仿真设计(Proteus仿真+程序设计+设计报告+讲解视频)
  • 基于R语言地理加权回归、主成份分析、判别分析等空间异质性数据分析实践技术应用
  • JVM 与容器化部署调优实践(Docker + K8s)
  • 前端excel表格解析为json,并模仿excel显示
  • 【HarmonyOS Next之旅】DevEco Studio使用指南(二十五) -> 端云一体化开发 -> 业务介绍(二)
  • 心知天气 API 获取天气预报 2025/5/21
  • 基于springboot+vue网页系统的社区义工服务互动平台(源码+论文+讲解+部署+调试+售后)
  • NSSCTF [watevrCTF 2019]Wat-sql
  • MCP和 AI agent 有什么区别和联系
  • 【工具教程】图片识别内容改名,图片指定区域识别重命名,批量识别单据扫描件批量改名,基于WPF和腾讯OCR的实现方案
  • 【VLNs篇】03:VLMnav-端到端导航与视觉语言模型:将空间推理转化为问答
  • Linux:进程信号---信号的保存与处理
  • 上海网站制作工作室/常州网站seo
  • 帮客户做网站平台犯法吗/免费创建属于自己的网站
  • 烟台网站建设哪家服务好/百度推广开户渠道公司
  • 政府网站建设服务商/海外免费网站推广有哪些
  • 比特币做游戏币的网站/营销策划书范文案例
  • windows不能用wordpress/长清区seo网络优化软件