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秒后重试}
}

应用场景

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

注意事项

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

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

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

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

相关文章

Redisson分布式集合原理及应用

Redisson是一个用于Redis的Java客户端&#xff0c;它简化了复杂的数据结构和分布式服务的使用。 适用场景对比 数据结构适用场景优点RList消息队列、任务队列、历史记录分布式共享、阻塞操作、分页查询RMap缓存、配置中心、键值关联数据支持键值对、分布式事务、TTLRSet去重集…

打破次元壁,VR 气象站开启气象学习新姿势​

在教育领域&#xff0c;VR 气象站同样发挥着巨大的作用&#xff0c;为气象教学带来了全新的模式&#xff0c;打破了传统教学的次元壁&#xff0c;让学生们以全新的姿势学习气象知识。​ 在传统的气象教学中&#xff0c;学生们主要通过课本、图片和老师的讲解来学习气象知识。这…

k8s面试题-ingress

场景&#xff1a;我通过deployment更新pod&#xff0c;ingress是怎么把新的请求流量发送到我新的pod的&#xff1f;是怎么监控到我更新的pod的&#xff1f; 在 Kubernetes 中&#xff0c;Ingress 是一种 API 对象&#xff0c;用于管理外部访问到集群内服务的 HTTP 和 HTTPS 路…

RHCE 练习三:架设一台 NFS 服务器

一、题目要求 1、开放 /nfs/shared 目录&#xff0c;供所有用户查询资料 2、开放 /nfs/upload 目录&#xff0c;为 192.168.xxx.0/24 网段主机可以上传目录&#xff0c;并将所有用户及所属的组映射为 nfs-upload,其 UID 和 GID 均为 210 3.将 /home/tom 目录仅共享给 192.16…

【动态导通电阻】GaN HEMT动态导通电阻的精确测量

2023 年 7 月,瑞士洛桑联邦理工学院的 Hongkeng Zhu 和 Elison Matioli 在《IEEE Transactions on Power Electronics》期刊发表了题为《Accurate Measurement of Dynamic ON-Resistance in GaN Transistors at Steady-State》的文章,基于提出的稳态测量方法,研究了氮化镓(…

AI 制作游戏美术素材流程分享(程序员方向粗糙版)

AI 制作游戏美术素材分享(程序员方向粗糙版) 视频讲解: 抖音:https://www.douyin.com/user/self?from_tab_namemain&modal_id7505691614690561295&showTabpost Bilibili: https://www.bilibili.com/video/BV1ojJGzZEve/ 写在最前面: 本方法比较粗糙,只对对美术风…

Java求职面试:互联网大厂技术栈深度解析

文章简述 在这篇文章中&#xff0c;我们将通过一个模拟的面试场景&#xff0c;带你深入了解Java求职面试中可能会遇到的技术栈问题。通过这个故事&#xff0c;你可以学习到相关技术点的具体应用场景和面试技巧。 正文 场景&#xff1a;某互联网大厂的面试现场 面试官&#…

学习日记-day11-5.20

完成目标&#xff1a; comment.java package com.zcr.pojo; import org.hibernate.annotations.GenericGenerator;import javax.persistence.*; //JPA操作表中数据&#xff0c;可以将对应的实体类映射到一张表上Entity(name "t_comment")//表示当前的实体类与哪张表…

机器学习第十九讲:交叉验证 → 用五次模拟考试验证真实水平

机器学习第十九讲&#xff1a;交叉验证 → 用五次模拟考试验证真实水平 资料取自《零基础学机器学习》。 查看总目录&#xff1a;学习大纲 关于DeepSeek本地部署指南可以看下我之前写的文章&#xff1a;DeepSeek R1本地与线上满血版部署&#xff1a;超详细手把手指南 交叉验证…

Linux面试题集合(6)

创建多级目录或者同级目录 mkdir -p 文件名/文件名/文件名 mkdir -p 文件名 文件名 文件名 Linux创建一个文件 touch 文件名 DOS命令创建文件 echo 内容>文件名&#xff08;创建一个有内容的文件&#xff09; echo >文件名&#xff08;创建一个没有内容的文件&#xff09…

Vue百日学习计划Day46-48天详细计划-Gemini版

Day 46: <KeepAlive> - 组件缓存与优化 (~3 小时) 本日目标: 理解 <KeepAlive> 的作用&#xff0c;学会如何使用它来缓存组件实例&#xff0c;从而优化应用性能和用户体验。所需资源: Vue 3 官方文档 (<KeepAlive>): https://cn.vuejs.org/guide/built-ins/…

SpringBean模块(三)具有生命周期管理能力的类(1)AutowireCapableBeanFactory

一、介绍 1、简介 AutowireCapableBeanFactory 是 Spring 框架中的一个接口&#xff0c;位于 org.springframework.beans.factory 包下&#xff0c;它提供了更底层的 Bean 实例化、依赖注入和生命周期管理能力&#xff0c;即使这些 Bean 没有通过常规的 Component 或 XML 注册…

Service Mesh

目录 一、Service Mesh 的核心特点 二、Service Mesh 的典型架构 1. Sidecar 模式 2. 控制平面与数据平面分离 三、Service Mesh 解决的核心问题 四、典型应用场景 五、主流 Service Mesh 框架对比 六、挑战与局限性 七、未来趋势 总结 Istio 一、Istio 核心组件与…

黑马Java基础笔记-13常用查找算法

查找算法 基本查找(也叫顺序查找&#xff0c;线性查找) 二分查找&#xff08;需要有序数据&#xff09; public static int binarySearch(int[] arr, int number){//1.定义两个变量记录要查找的范围int min 0;int max arr.length - 1;//2.利用循环不断的去找要查找的数据wh…

Go 语言 vs C+Lua(Skynet)游戏服务器方案对比分析

为啥挑这两个呢&#xff1f;因为两种技术分别对应CSP模型和Actor模型&#xff0c;都是经过时间检验的成熟且可靠的并发模型&#xff0c;问了很多地方&#xff0c;经过gpt整理得出如下报告。 从开发效率、运行性能、热更新扩展、云部署与水平扩展能力、多类型游戏支持等五个维度…

LeetCode 925. 长按键入 java题解

双指针。不会写。 https://leetcode.cn/problems/long-pressed-name/description/ class Solution {public boolean isLongPressedName(String name, String typed) {int len1name.length();int len2typed.length();int i0,j0;while(i<len1&&j<len2){if(name.ch…

如何使用通义灵码提高前端开发效率

工欲善其事&#xff0c;必先利其器。对于前端开发而言&#xff0c;使用VSCode已经能够极大地提高前端的开发效率了。但有了AI加持后&#xff0c;前端开发的效率又更上一层楼了&#xff01; 本文采用的AI是通义灵码插件提供的通义千问大模型&#xff0c;是目前AI性能榜第一梯队…

【小明剑魔视频Viggle AI模仿的核心算法组成】

Viggle AI 作为一款先进的生成式视频AI工具&#xff0c;其核心技术栈融合了多项前沿算法。以下是深度解析其核心算法架构及实现原理&#xff1a; 一、核心算法组成 1. 运动控制生成&#xff08;Motion Control Generation&#xff09; 算法框架&#xff1a;基于扩散模型&…

解决Power BI Desktop导入Excel数据第一行不是列标题问题

选中第一行不是列标题的表→鼠标右键→选择编辑查询→进入Power Query界面→点击“将第一行用作标题”→点击左边的“关闭并应用” 第一行就提升为标题了

对 Lambda 架构问题的深入理解

感谢 GPT&#xff0c;对很多问题的理解有机会更深。 大家攻击 Lambda 架构&#xff0c;常说的一个点就是 “实时离线指标存在差异”。“实时离线指标存在差异”&#xff0c;是一个真实困扰运营方的问题吗&#xff1f; 答案&#xff1a;是的&#xff0c;这是一个真实生活中的痛…