正确的 Java 异常处理
我们来谈谈痛点吧。由于我的职责,我必须使用许多不同的服务(进行编辑、进行代码审查......);不同的团队通常会编写所有这些服务,每当涉及到处理错误并从服务转发错误时,有时我的眼睛就会开始流泪。让我尝试告诉您哪些代码在我看来是不可接受的错误处理以及我认为应该如何处理。
一般来说,最初问题隐藏在服务分析的缺陷中。通常,对于如何抛出错误没有参考要求。一般来说,发生这种情况有两个原因:第一个是急于开发新服务,第二个是分析师信任开发人员的经验。在这种情况下,分析师只需告诉开发人员:“好吧,稍后给我一个错误消息的示例,我将在汇合中附加它。”
让我们继续看例子;让我们看看这种方法在开发中的后果。
首先不要做的就是抛出 RuntimeException:
public Object badExample() {throw new RuntimeException("Something wrong!");
}
展示:
调用服务或客户端将收到 500 错误,并且无法理解其请求出了什么问题。您认为在这种情况下需要多长时间才能发现问题?它会随着你的代码量成比例增长。如果你有一个方法调用链,那么在服务内部调用方法时处理此类消息就会变得更加困难。
如何改进呢?首先,让我们创建一个错误处理程序;几乎所有框架都开箱即用;在我的示例中,我将使用 Spring 框架处理程序。
例子:
@ControllerAdvice
public class ApiExceptionHandler {@ExceptionHandler(value = {RuntimeException.class})public ResponseEntity<Object> handler(RuntimeException e) {HttpStatus badRequest = HttpStatus.INTERNAL_SERVER_ERROR;return new ResponseEntity<>(e.getMessage(), badRequest);}...
展示:
现在我们看到了消息,但是消息的格式是字符串,而不是 JSON。我们很快就会解决这个问题。
理想情况下,项目中的所有服务都应具有相同的错误消息格式。至少有两个字段是消息本身和内部整数错误代码。我想没有必要说明为什么消息文本不足以及需要多少资源来处理该字符串。
例子:
public class ExampleApiError {private String message;private Integer code;private LocalDateTime dateTime;...
我们将在错误处理程序中填充此类。但正如我所说,抛出 RuntimeException 是一种不好的做法,因此您需要创建自己的类来抛出错误,在该类的构造函数中我们将传递一条消息和一个错误代码。
public class ApiException extends RuntimeException {private final int code;public ApiException(String msg, int code) {super(msg);this.code = code;}...
似乎一切都更加清楚了,但即使在这里,问题也开始了;每个人都以不同的方式创建传递给类构造函数的参数。有些直接在方法中创建消息和错误代码。
例子:
public Object badExample() {throw new ApiException("Something wrong!", 10);
}
在代码中找到这样的地方仍然很困难。嗯,首先想到的是创建常量类,一个类用于消息,第二个类用于消息代码。
例子:
public static final String SOMETHING_WRONG = "Something wrong";
public static final int SOMETHING_WRONG_CODE = 10;public Object badExample() {throw new ApiException(SOMETHING_WRONG, SOMETHING_WRONG_CODE);
}
当您知道错误代码在哪里时,这已经更好、更具可读性并且更容易找到。
但是,如果您没有微服务,那么将所有内容存储在一个类中可能不是一个好主意。消息开始变得越来越大,因此最好根据方法的功能来分离常量类,这些常量类将与 ProductExceptionConstant、PaymentExceptionConstant 等一起使用。
但这还不是全部。对某些人来说,这可能看起来很过时,但常量需要创建为枚举或接口。接口中的变量默认是静态的、公共的和最终的。我并不反对这种做法;最重要的是一切都应该是统一的;如果您开始通过接口进行操作,则继续这样做;无需混合。在其中一个项目中,我看到同一团队使用三种不同的常量方法。你不必这样做。)
我将再展示一个在审核过程中引起我注意的真实项目的示例。
首先,开发人员决定他返回的所有实体都将包含错误消息和错误代码,并且状态将始终为 200,在我看来,这会误导调用者。嗯,一个常量的例子。
public enum ErrorsEnum {DEFAULT_ERROR(ErrorsConstants.DEFAULT_ERROR, "400"),REFRESH_TOKEN_NOT_VALID(ErrorsConstants.REFRESH_TOKEN_NOT_VALID, "400.1"),USER_NOT_FOUND(ErrorsConstants.USER_NOT_FOUND, "400.2"),
在我看来,代码 9 3 \ 4 丢失了。默认情况下,在这种情况下,您可以使用数字 Pi。
如果您对我的方法感兴趣,那就继续吧。最方便的事情是创建一个接口,它将成为每个人都有约束力的契约。
public interface ExceptionBase {String getMsg();Integer getCode();
}
并且需要更改异常类的构造函数。
public ApiException(ExceptionBase e) {super(e.getMsg());this.code = e.getCode();
}
现在,每个尝试抛出异常的人都会明白,我们必须将实现接口的对象传递给构造函数。最合适的选择是 Enum。
例子:
/*** This class is intended for declaring exceptions that occur during order processing. code range* 101-199.*/
public enum OrderException implements ExceptionBase {ORDER_NOT_FOUND("Order not found.", 101),ORDER_CANNOT_BE_UPDATED("Order cannot be updated,", 102);OrderException(String msg, Integer code) {this.msg = msg;this.code = code;}private final String msg;private final Integer code;@Overridepublic String getMsg() {return msg;}@Overridepublic Integer getCode() {return code;}
}
使用示例:
public Object getProduct(String id) {if (id.equals("-1")) {throw new ApiException(OrderException.ORDER_NOT_FOUND);}
...
服务器响应:
因此,我们有以下异常包模型。
正如您所看到的,没什么复杂的;逻辑很容易阅读。在此示例中,我在 ApiException 类中留下了一个接受字符串的构造函数,但为了可靠性,最好将其删除。
通常,代码中的大多数不一致都是由于缺乏代码检查或检查不力造成的。最常见的借口是,“这是一个临时解决方案;我们稍后会修复它”,但不,它不会那样工作;没有人会费心寻找哪里有临时解决方案,哪里有永久解决方案。事实证明,“暂时的就是永久的”。
如果您有很多相互通信的服务,那么通过制作一种错误消息格式,您将大大简化编写客户端库的工作。例如,使用Retrofit时,一旦编写了处理程序核心,您只需更改接口中的方法和接收的对象即可。
结论
错误处理是代码中非常重要的部分;它可以轻松地找到代码中的问题区域,并且还允许外部客户端了解他们在使用端点时做错了什么,因此您应该从编写项目的第一阶段就对此给予适当的关注。
示例代码在这里。
我希望读完这篇文章后你的生活会变得更轻松一些。一切成功。
相关文章:

正确的 Java 异常处理
我们来谈谈痛点吧。由于我的职责,我必须使用许多不同的服务(进行编辑、进行代码审查......);不同的团队通常会编写所有这些服务,每当涉及到处理错误并从服务转发错误时,有时我的眼睛就会开始流泪。让我尝试…...

RTT(RT-Thread)时钟管理
目录 时钟管理 时钟节拍 RTT工程目录结构介绍 配置文件:rtconfig.h 获取系统节拍 获取系统节拍数函数 实例 定时器 RT_Thread定时器介绍 定时器源码分析(了解即可) rt_system_timer_init (硬件定时器初始化) rt_system_timer_thr…...

基础实验篇 | uORB消息读写与自定义实验(二)
导读 uORB是PX4/Pixhawk系统中非常重要且关键的模块之一,是用于无人机模块间通信的协议机制。本篇将详细介绍uORB并详细拆解uORB消息读写与自定义实验全流程(二)。 基础实验篇 | uORB消息读写与自定义实验(二) 01 RflySim平台的uORB消息读写…...

k8s pod数据存储Volumes
一、说在前面的话 在 Kubernetes 的 Deployment 中,您可以使用多种类型的 Volumes 来管理 Pod 中的数据。 作用是用来共享目录及配置,不用在每个pod里进行配置。 本文主要概述怎么使用HostPath、PersistentVolumeClaim、ConfigMap。 二、k8s有哪些Vol…...

ZYNQ在Petalinux系统下双网口同网段的实现
ZYNQ在Petalinux系统下双网口同网段的实现 1.开发环境 采用了赛灵思zynq xc7z100芯片,外部挂载了两个网口phy芯片(marvell 88e1510),且两个网口phy芯片公用MDIO管脚,bd配置如下: 2.问题说明 忙去了&am…...

突破传统监测模式:业务状态监控HM的新思路 | 京东云技术团队
一、传统监控系统的盲区,如何打造业务状态监控。 在系统架构设计中非常重要的一环是要做数据监控和数据最终一致性,关于一致性的补偿,已经由算法部的大佬总结过就不再赘述。这里主要讲如何去补偿?补偿的方案哪些?这就…...
7-16 验证“哥德巴赫猜想” (20 分)
7-16 验证“哥德巴赫猜想” (20 分) 数学领域著名的“哥德巴赫猜想”的大致意思是:任何一个大于2的偶数总能表示为两个素数之和。比如:24519,其中5和19都是素数。本实验的任务是设计一个程序,验证20亿以内的偶数都可以…...

GEE学习02 --设置Jupyter Notebook的打开路径
直接双击Jupyter Notebook 桌面图标运行时,打开的文件路径是默认的:C:\用户\用户名 如果使用python命令提示符打开jupyter notebook , 而我新建的GEE学习文件夹在另一个路径,可以直接修改默认的保存路径:…...

stm32与上位机电脑间最快的通信方式是什么?
对于小型多关节机械臂的控制电路设计,选择合适的通信方式可以提高MCU与上位机之间的实时性。以下是一些在STM32上常用的通信方式,你可以根据你的具体需求选择适合的: 串口通信(UART):串口通信是一种常见的…...

pytorch学习——卷积神经网络——以LeNet为例
目录 一.什么是卷积? 二.卷积神经网络的组成 三.卷积网络基本元素介绍 3.1卷积 3.2填充和步幅 3.2.1填充(Padding) 填充是指在输入数据周围添加额外的边界值(通常是零),以扩展输入的尺寸。填充可以在卷…...

stm32 mpu6050 cubemx DMP法读取角度
文章目录 前言一、相关文件二、cubemx配置三、代码变量初始化主循环 总结 前言 文件 记录使用dmp库来读取mpu6050的角度。 这是参考文件 参考1–主要参考 github参考 参考2 参考三 一、相关文件 相关文件在这里下载(未填,不过可以在上面的git中下载&a…...

.Net6 Core Web API 配置 log4net + MySQL
目录 一、导入NuGet 包 二、添加配置文件 log4net.config 三、创建MySQL表格 四、Program全局配置 五、帮助类编写 六、效果展示 小编没有使用依赖注入的方式。 一、导入NuGet 包 ---- log4net 基础包 ---- Microsoft.Extensions.Logging.Log4Net…...

校园跑腿小程序运营攻略
作为一名校园跑腿小程序的运营者,你可能会面临诸如用户获取、平台推广、服务质量保证等挑战。在本篇推文中,我将为你提供一些关键的运营策略,帮助你成功运营校园跑腿小程序。 1. 用户获取和留存 用户是校园跑腿小程序成功的关键。以下是一些…...

InfluxDB2如何求增量数据
需求 项目中需要接入电表设备,求用电量。 按天和设备统计用电量 按天统计用电量 统计总用电量 存在的问题 difference 函数可以求增量,但是以上计算均存在一个问题,比如xx设备有8.1号和8.2号的数据,我统计每天的用电量…...

Flink作业调度的9种状态
1.什么是作业调度 Flink 通过 Task Slots 来定义执行资源。每个 TaskManager 有一到多个 task slot,每个 task slot 可以运行一条由多个并行 task 组成的流水线。 这样一条流水线由多个连续的 task 组成,比如并行度为 n 的 MapFunction 和 并行度为 n 的…...
8、Kubernetes核心技术 - ConfigMap
目录 一、ConfigMap概述 二、ConfigMap创建 2.1、命令行方式创建 2.2、yaml 文件方式创建 三、ConfigMap查询 四、ConfigMap更新 4.1、kubectl edit方式 4.2、kubectl apply方式 五、ConfigMap使用 5.1、spec.env 【环境变量】 5.2、spec.envFrom 【环境变量】 5.3…...

音视频--DTMF信号发送及检测
参考资料 https://zh.wikipedia.org/wiki/%E5%8F%8C%E9%9F%B3%E5%A4%9A%E9%A2%91https://www.cnblogs.com/lijingcheng/p/4454932.html 1. DTMF是什么 1.1 DTMF定义 双音多频信号(英语:Dual-Tone Multi-Frequency,简称:DTMF&a…...

阿里云容器服务助力极氪荣获 FinOps 先锋实践者
作者:海迩 可信云评估是中国信息通信研究院下属的云计算服务和软件的专业评估体系,自 2013 年起历经十年发展,可信云服务评估体系已日臻成熟,成为政府支撑、行业规范、用户选型的重要参考。 2022 年 5 月国务院国资委制定印发《…...
C++ 通过time.windows.com获取时间
C++ 通过time.windows.com获取时间 在C++中,你可以使用 <ctime>头文件中的 time()函数来获取当前的系统时间。然后,你可以使用 <ctime>头文件中的 localtime()函数将时间转换为本地时间,并从中获取小时、分钟和秒。 以下是一个示例代码,演示如何通过time.windo…...

MPLAB加载c文件为什么不能添加到工程中的source files中
MPLAB加载c文件为什么不能添加到工程中的source files中 因为你安装好MAPLAB软件之后你的编译器是默认的编译器,所以当你添加C文件时,软件是不认识C文件的,只有手动的将编译器改成自安装的PICC编译器才能进行C文件的正确加载。 具体修改步骤…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...

【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...