正确的 Java 异常处理

news2024/11/27 8:31:38

        我们来谈谈痛点吧。由于我的职责,我必须使用许多不同的服务(进行编辑、进行代码审查......);不同的团队通常会编写所有这些服务,每当涉及到处理错误并从服务转发错误时,有时我的眼睛就会开始流泪。让我尝试告诉您哪些代码在我看来是不可接受的错误处理以及我认为应该如何处理。

        一般来说,最初问题隐藏在服务分析的缺陷中。通常,对于如何抛出错误没有参考要求。一般来说,发生这种情况有两个原因:第一个是急于开发新服务,第二个是分析师信任开发人员的经验。在这种情况下,分析师只需告诉开发人员:“好吧,稍后给我一个错误消息的示例,我将在汇合中附加它。”

        让我们继续看例子;让我们看看这种方法在开发中的后果。

首先不要做的就是抛出 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;

  @Override
  public String getMsg() {
    return msg;
  }

  @Override
  public Integer getCode() {
    return code;
  }
}

使用示例:

public Object getProduct(String id) {
  if (id.equals("-1")) {
    throw new ApiException(OrderException.ORDER_NOT_FOUND);
  }
...
 

服务器响应:

 因此,我们有以下异常包模型。

 

正如您所看到的,没什么复杂的;逻辑很容易阅读。在此示例中,我在 ApiException 类中留下了一个接受字符串的构造函数,但为了可靠性,最好将其删除。

通常,代码中的大多数不一致都是由于缺乏代码检查或检查不力造成的。最常见的借口是,“这是一个临时解决方案;我们稍后会修复它”,但不,它不会那样工作;没有人会费心寻找哪里有临时​​解决方案,哪里有永久解决方案。事实证明,“暂时的就是永久的”。

如果您有很多相互通信的服务,那么通过制作一种错误消息格式,您将大大简化编写客户端库的工作。例如,使用Retrofit时,一旦编写了处理程序核心,您只需更改接口中的方法和接收的对象即可。

结论

错误处理是代码中非常重要的部分;它可以轻松地找到代码中的问题区域,并且还允许外部客户端了解他们在使用端点时做错了什么,因此您应该从编写项目的第一阶段就对此给予适当的关注。

示例代码在这里。

我希望读完这篇文章后你的生活会变得更轻松一些。一切成功。

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

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

相关文章

elasticsearch-head可视化安装

一、前言 elasticsearch-head 是用于监控 Elasticsearch 状态的客户端插件&#xff0c;包括数据可视化、执行增删改查操作等。 elasticsearch是通过API方式进行管理的&#xff0c;因此也可以使用postman等工具操作elasticsearch。 二、安装 lasticsearch-head插件是使用Jav…

供应链云仓系统的源码解析

1. 什么是供应链云仓系统 供应链云仓系统是一种基于云计算和大数据技术的物流管理系统&#xff0c;旨在提高供应链的效率和运作能力。该系统通过集成各环节的物流信息&#xff0c;实现实时数据共享和流程连接&#xff0c;从而优化物流运营、提升客户满意度。 2. 源码解析&#…

机器学习深度学习——常见循环神经网络结构(RNN、LSTM、GRU)

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位即将上大四&#xff0c;正专攻机器学习的保研er &#x1f30c;上期文章&#xff1a;机器学习&&深度学习——RNN的从零开始实现与简洁实现 &#x1f4da;订阅专栏&#xff1a;机器学习&&深度学习 希望文章…

SD-MTSP:杨氏双缝实验优化算法YDSE求解单仓库多旅行商问题MATLAB(可更改数据集,旅行商的数量和起点)

一、杨氏双缝实验优化算法YDSE 杨氏双缝实验优化算法&#xff08;Young’s double-slit experiment optimizer&#xff0c;YDSE&#xff09;由Mohamed Abdel-Basset等人于2023年提出。 参考文献&#xff1a; [1]Mohamed Abdel-Basset, Doaa El-Shahat, Mohammed Jameel, Moha…

阿里云轻量应用服务器_2核2G3M_108元/年_性能测评

阿里云轻量应用服务器2核2G3M带宽108元一年&#xff0c;系统盘为50GB高效云盘&#xff1b;轻量服务器2核4G4M带宽&#xff0c;60GB高效云盘297.98元12个月。目前轻量应用服务器只有2核2G和2核4G有活动&#xff0c;阿里云百科分享阿里云轻量应用服务器入口&#xff1a; 目录 阿…

【Mybatis】调试查看执行的 SQL 语句

1. 问题场景&#xff1a; 记录日常开发过程中 Mybatis 调试 SQL 语句&#xff0c;想要查看Mybatis 中执行的 SQL语句&#xff0c;导致定位问题困难 2. 解决方式 双击shift找到mybatis源码中的 MappedStatement的getBoundSql()方法 public BoundSql getBoundSql(Object para…

贝锐蒲公英:快速搭建连锁门店监控体系,赋能企业高效管理

随着国民生活水平的提高和零售场景的变革&#xff0c;消费者对于餐饮类目的消费支出不断增加&#xff0c;线下社区生鲜商超作为下沉市场最主要的消费场景之一&#xff0c;蕴藏着巨大价值机会。 对于线下连锁生鲜超市而言&#xff0c;连锁门店多、员工多&#xff0c;门店管理时会…

大学生课设实训|基于springboot的在线拍卖系统

目录 项目描述 主要技术栈 功能效果 数据库设计 开发顺序 业务功能 大家好&#xff01;我是龍弟-idea&#xff01;需要源码资料信息可私聊我【HWL__666666】&#xff01; 项目描述 本系统是一个网上商品竞拍系统&#xff0c;为拍卖者和竞买者提供一个在线交流平台。本项…

【一口气 Ping 1000 个 IP 地址,会发生什么事情?】

ping命令是我们检查网络中最常用的命令&#xff0c;作为网络人员&#xff0c;基本上每天都会用到&#xff0c;可以很好地帮助我们分析和判定网络故障&#xff0c;对吧&#xff1f; 一般来说&#xff0c;网工们用 ping查看网络情况&#xff0c;主要是检查两个指标&#xff1a; …

css3 实现文字横幅无缝滚动

css3 实现文字横幅无缝滚动 使用 css3 关键帧 keyframes 和 animation 属性实现文字横幅无缝滚动。 <template><div class"skiHallBanner"><div class"skiHallBanner-text"><span>{{ text }}</span></div></div>…

嵌入式开发:高薪与广阔前景

嵌入式开发是高薪且前景广阔的领域。随着物联网和智能化的快速发展&#xff0c;嵌入式开发人才需求不断增加&#xff0c;市场供应相对不足&#xff0c;导致竞争激烈&#xff0c;推动了薪资水平的提升。 嵌入式开发的复杂性和技术要求使得企业为了吸引优秀人才&#xff0c;普遍…

并发——ThreadPoolExecutor 使用示例

文章目录 1 示例代码:RunnableThreadPoolExecutor2 线程池原理分析3 几个常见的对比3.1 Runnable vs Callable3.2 execute() vs submit()3.3 shutdown()VSshutdownNow()3.2 isTerminated() VS isShutdown() 4 加餐:CallableThreadPoolExecutor示例代码 我们上面讲解了 Executor…

数据结构——时间复杂度和空间复杂度

1.算法效率 2.时间复杂度 3.空间复杂度 4. 常见时间复杂度以及复杂度oj练习 1.算法效率 1.1 如何衡量一个算法的好坏 如何衡量一个算法的好坏呢&#xff1f;比如对于以下斐波那契数的计算 long long Fib(int N) { if(N < 3) return 1; return Fib(N-1) Fib(N-2); }我们看到…

如何提高商城系统的稳定性?

电商行业的飞速发展&#xff0c;越来越多的企业开始关注电商建设。其中&#xff0c;商城系统的稳定性是企业最为关心的问题之一。 商城系统的稳定性不仅影响用户体验&#xff0c;还关系到企业的声誉和利益。因此&#xff0c;如何提高商城系统的稳定性是每一个电商企业必须要面对…

高忆管理:股票集合竞价?

股票集合竞价&#xff08;英文缩写为“SPAC”&#xff09;是股票商场开市前最终一个阶段&#xff0c;也被称为“开盘竞价”。在这个阶段&#xff0c;买卖双方能够提交订单&#xff0c;而且体系将会平衡对买卖盘进行撮合&#xff0c;以确认股票开盘价。这个阶段通常会在上午九点…

AnyCase4.0全球贸易集成平台震撼上线,免费试用赢取精美好礼!

全球贸易行业一直以来都面临着各种挑战和复杂的操作流程。然而&#xff0c;随着科技的不断进步和跨境贸易的日益发展&#xff0c;一个集物流服务、外贸服务、供应商管理和企业风控管理于一体的全新跨境贸易集成平台AnyCase4.0应运而生。经过多年的沉淀和精心打磨&#xff0c;An…

树结构转换

思路&#xff1a; 先把数组转化成一个对象&#xff08;map&#xff09;&#xff0c;对象的key值是对象的id 遍历对象&#xff1b;map[map[k].pid].children.push(map[k]),【k代表索引】&#xff0c;pid等于0代表是根节点 // 数结构转换let arr [{id: 1,pid: 0,name: "b…

【606. 根据二叉树创建字符串】

目录 1.题目描述2.算法思想3.代码实现 1.题目描述 这道题的重点其实就是要省去不影响映射的括号。如&#xff1a; 2.算法思想 3.代码实现 class Solution { public:string _tree2str(TreeNode* root,string& ret){if(rootnullptr){return "";}retto_string(ro…

考研不是在职提升的唯一的途径,还有免联考的社科院与杜兰大学金融管理硕士

社会的迅猛发展&#xff0c;职场竞争愈发激烈&#xff0c;许多人选择考研来提升自己的竞争力&#xff0c;因此考研人数也是逐年增加。根据研招网官方统计&#xff0c;2023年研究生报考人数为474万&#xff0c;相较去年22考研全国硕士研究生招生考试报名人数457万人&#xff0c;…

网盘直链下载助手

一、插件介绍 1.介绍 这是一款免费开源获取网盘文件真实下载地址的油猴脚本&#xff0c;基于 PCSAPI&#xff0c;支持 Windows&#xff0c;Mac&#xff0c;Linux 等多平台&#xff0c;支持 IDM&#xff0c;XDown&#xff0c;Aria2 等多线程下载工具&#xff0c;支持 JSON-RPC…