通过适当的异常处理进行快速调试

news2024/12/22 19:49:46

编写良好的代码和异常处理

作为开发人员,开发中最令人恼火的部分通常是调试。与我共事过的大多数程序员都会赞同这种观点。通常,看到异常的第一反应是烦恼和沮丧的混合。易于调试的异常通常会在调试后的几分钟内产生根本原因。最让我烦恼的是那些在系统在生产中正常运行几天后发生的那些,它们的堆栈跟踪导致死胡同。但是,编写良好的代码可以正确管理异常,不仅可以帮助您更快地调试问题,而且在某些情况下,可以帮助系统自动恢复而无需干预。

幸运的是,您可以使用一些简单有效的工具来减少调试后一种异常所花费的时间。通常,这种技术并不能真正提高您正在开发的软件的可靠性(至少一开始不会),但是从根本上解决问题并提出修复方法变得更加容易。

何时不使用例外?

在深入了解异常处理的详细信息之前,了解何时根本不使用异常至关重要。请考虑以下方案,其中客户端希望通过发送“QUIT”命令来关闭与服务器的会话。

退出命令

由于各种原因,这是对例外的可怕使用。

  • 异常在实现和可维护性方面都很难遵循: 既然这是预期的,你的客户如何知道是真的出了问题,还是这只是一个预期的异常?在客户端正常关闭会话的代码将与此服务可能发生的其他异常混合在一起。想象一下,如果您是客户团队的开发人员。遵循异常处理代码中发生的事情不会令人沮丧吗?
  • 发出异常情况的信号是困难的:您正在使用异常来处理正常的代码流。发生实际异常时的计划是什么?如果客户端错误捕获了通用异常而不是此特定异常,会发生什么情况?
  • 性能:发生异常时,程序控制堆栈将被抛出窗口,并且正常的调用堆栈例程将中断。由于异常预计仅在异常情况下发生,因此这些进程的性能通常不是运行时的最高优先级。

总而言之,请始终记住,只有在“异常”情况下才应引发异常。

Java 中的异常基础知识

错误与异常/捕获可抛出量与异常

错误是 Throwable 的一个子类,它指示合理的应用程序不应尝试捕获的严重问题。大多数此类错误都是异常情况。 ThreadDeath 错误虽然是“正常”情况,但它也是 Error 的一个子类,因为大多数应用程序不应尝试捕获它。捕获可投掷物会捕获所有错误。由于可投掷物是在极端条件下产生的,因此您几乎永远不会从中恢复过来。因此,捕获可抛出物不仅是一种糟糕的设计实践,而且还可能导致意想不到的后果,从而使应用程序更难调试。

选中的异常与未选中的异常

让我们看一下 Java 中异常的层次结构。

选中和未选中的异常都继承自泛型“异常”类(至少是间接继承);但是,它们在使用中具有非常不同的目的。

引发选中的异常会强制调用方考虑他们想要对异常执行的操作。他们不能简单地忽视它。他们要么需要捕获它并对其进行处理,要么将其显式扔回调用方。这是因为 Java 编译器不允许您编译可以接收已检查异常并忽略它的方法调用。

 未经检查的异常是纯粹的运行时异常。通常,您不会期望所有调用方都知道可以从应用程序代码引发的每个运行时异常。调用方不需要显式考虑引发运行时异常时要执行的操作。

我经常遵循的一般经验法则是,当您的调用者想要捕获异常并对其进行处理时,使用检查异常。这条规则确实带有一粒盐。如果您在 UI 层并进行服务调用怎么办?您可能希望捕获所有异常,而不是在屏幕上显示 Java 堆栈跟踪。

引发特定异常

你见过多少次看起来像这样的代码?

通常,这是编写代码时最容易错过的错误。您反对截止日期,异常处理可能是您考虑的最后一件事。

引发泛型异常会严重妨碍调用方以不同的方式处理不同异常的能力。在这里,调用方明确需要捕获泛型异常,也许可以执行一些字符串魔术来了解代码的问题是什么,然后适当地处理它。相反,如果您只是抛出更具体的异常,则调用方可以通过捕获不同类型的异常并以不同的方式或按照程序的决定处理每个异常来清楚地了解发生了什么错误。

永不吞咽异常

吞下例外是危险的,在任何地方几乎没有例外。下面是一个简单的示例,用于演示可能发生的问题。

当数据库调用的可靠性为 99.999% 时,假设 0.001% 的调用将值保留在数据库中失败;您最有可能收到需要调试的用户投诉是什么?“即使交易被标记为成功,账户中也没有存入资金。”这似乎是一个从未发生过(或很少发生)的场景,但在我在软件行业工作期间,我遇到了 100 多个实例,在这些实例中,我阅读了与此类似的代码。忘记从异常中恢复;这里的调用者只是不知道是否有异常。作为收到此错误报告的开发人员,您不知道出了什么问题。数据库连接有问题吗?还是您被数据库限制?即使是像异常发生在哪里这样的基本问题也变得无法回答。

不要丢失堆栈跟踪

我经常观察到的一个常见且简单的错误是看起来像这样的代码。

 

与前面的示例不同,此处您知道错误发生的位置。当您进行持久函数调用时,它发生了。但是,一旦您知道此时发生了不好的事情,您想如何处理错误?当您查看堆栈跟踪时,除了错误发生的位置之外,它不会告诉您太多。用户 ID 是否不正确?帐号有误吗?数据库保存操作是否失败?确保将堆栈跟踪传播到调用方是回答这些问题的简单方法。

对所有捕获块进行递归审核是发现系统中的任何漏洞的必要条件。

在这里,堆栈跟踪将精确地回答我们上面提出的问题。只需查看堆栈跟踪,您就会知道哪一行引发了异常。对所有捕获块进行递归审核是发现系统中的任何漏洞的必要条件。

快速故障

当我们尝试自动从故障中恢复时,通常会提出一些论点。随着时间的推移,这些方案中会出现更复杂和细微的问题,调试起来令人沮丧。让我们看一个例子。

想象一下,您正在引导一个服务,该服务根据可用的线程池大小运行一堆侦听器。现在假设其中一位开发人员在配置中或在访问配置以获取线程数时引入了拼写错误。没有什么是失败的;您的服务会引导,但延迟开始增加。我可以想象在某些情况下,您必须竭尽全力才能根除此问题的原因。

快速失败的代码完全避免了此问题。您希望使用某个方法,如果出现异常,则立即停止并向调用方返回异常。这种方法可以确保您的服务不会在不完全正确的情况下启动,从而避免后续的问题。

快速失败的代码完全避免了此问题。您希望使用某个配置。如果找不到配置,为什么不立即抛出?这样做不仅可以精确地查明问题,还可以在开发过程中发现问题,从而节省推送紧急修复的麻烦。

快速失败也意味着你在对代码状态做出假设的地方失败。让我们看另一个例子来理解这一点。

此代码可能导致死胡同堆栈跟踪。如果在调用进程方法时抛出 NullPointerException,你怎么知道函数的输入是空的还是“除数”是空的?相反,在除数的构造函数中添加非空断言的代码将立即让调试器知道这里出了什么问题。

清理资源

发生异常时清理任何资源实例对于避免内存泄漏至关重要。内存泄漏是一类棘手的错误,因为症状通常不容易与根本原因相关联。

在上面提到的示例中,如果扫描程序对象已正确实例化,但在从文件中读取数据时引发异常,则扫描程序对象永远不会关闭。相反,使用 Java 中的 try-with-resource 语义根本不担心这个问题。

结论

尽管每个人都讨厌例外,但它们必然会发生。Java 围绕适当的异常处理提供了一个出色的生态系统,这有助于使您的调试工作非常轻松。了解异常处理的基础知识对于良好的软件交付至关重要,我打算捕获一些方法,这些方法可以帮助提高代码的健壮性,并最终帮助减少调试代码所花费的时间

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

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

相关文章

vue实现多布局模式

1、目标效果 源码地址:multipal-layout-demo: vue2实现多布局暗黑模式 默认布局:头部宽度100%,侧边栏、内容区 顶部布局:头部宽度100%,内容区 侧边栏布局:侧边栏高度100%,头部、内容区 2、原理…

python+vue课堂教学效果实时评价系统

系统权限按管理员,教师和学生这三类涉及用户划分。 (a) 管理员;管理员使用本系统涉到的功能主要有:个人中心,学生管理,教师管理,教学视频管理,教学课件管理,类型管理,视频…

ArcGIS Pro导航工具

主要导航工具为浏览工具 、屏幕导航器 、书签 、转到XY工具 。 其它还包括链接视图、地图比例(2D)、场景高度(3D)、暂停并刷新绘制、照相机属性、在3D模式下导航、键盘快捷键等。 1 主要导航工具 地图和场景的默认工具为浏览工具…

【python视图3】networkx图操作示例

一、说明 根据定义,图是节点(顶点)以及已识别的节点对(称为边、链接等)的集合。在 NetworkX 中,节点可以是任何可哈希对象,例如文本字符串、图像、XML 对象、另一个图形、自定义节点对象等。 如…

如何区分高压和低压电阻接地系统

电阻接地系统或电阻接地中性线系统是通过一个或多个电阻在中性线和大地之间有意连接的系统。在这些系统中,接地故障期间造成的损坏远小于在牢固接地系统中接地故障期间造成的损坏,并且设备上的机械应力也大大降低。 电阻通常具有比接近接地点的系统电抗…

WIN10-22H2专业版_电脑维修人员专用装机系统镜像【04.20更新】

WIN10-22H2专业版是由站长亲自封装的电脑维修人员专用装机系统镜像,系统干净无广告,稳定长效不卡顿,适合电脑维修店用来维修电脑重装系统。此版本是WIN10系统里非常稳定的正式版本之一,适合在维修电脑时重装系统或者大批量装机使用…

2023-spring 1. 补给马车

🍎道阻且长,行则将至。🍓 🌻算法,不如说它是一种思考方式🍀 算法专栏: 👉🏻123 一、🌱2023-spring 1. 补给马车 题目描述:远征队即将开启未知的冒…

防晒服饰赛道持续加速扩容 未来行业集中度有望进一步提升

一、防晒服饰行业概述 国内防晒服饰市场主要包括具有防晒功能的衣服、伞具、帽子、墨镜、口罩、面罩、披肩、袖套及手套等产品。相比较防晒护肤品需要定时补涂、具有过敏风险、防晒效果欠佳以及消耗量大的缺陷,防晒服饰具有覆盖面广、使用方便、防晒效果好、对身体…

ChatGPT: 如何利用OpenAI的GPT-3.5构建智能对话助手

ChatGPT: 如何利用OpenAI的GPT-3.5构建智能对话助手 GPT-3.5:OpenAI的语言模型在自然语言处理领域的重要地位和应用潜力 GPT-3.5是OpenAI开发的一种强大的语言模型,具有广泛的应用潜力和在自然语言处理领域的重要地位。作为OpenAI最新一代的语言模型&…

初识C++之C++11

目录 一、C11的概念 二、统一的列表初始化 1.{ }初始化 2.initializer_list 三、decltype 四、lambda表达式 1. lambda表达式的出现原因 2. lambda表达式的使用 2.1 捕捉列表 2.2 参数列表 2.3 mutable 2.4 返回值类型 2.5 函数体 2.6 使用方式 3. lambda表达式…

c++积累11-强制类型转换运算符(static_cast/reinterpret_cast/const_cast/dynamic_cast)

1、背景 将类型名作为强制类型转换运算符的做法是C语言的老式做法,C为保持兼容而予以保留。强制类型转换是有一定风险的,C引入新的转换机制,主要为了客服C语言转换的三个缺点; 1、没有从形式上体现转换功能和风险的不同。 例如&a…

LeetCode特训 --- Week2 (主打滑动窗口 + 字符串匹配题目)

目录 滑动窗口原理 真懂了滑动窗口? 滑动 字符串细节 开干切题 滑动窗口原理 滑动窗口:维护一前一后两根指针, 或者说一左一右两个指针。更主要的是维护左右指针中的区间. 同时不断的向前滑动,直到整个序列滑动结束,前指针走到序列末尾…

总结:Grafana Mimir调用

一、背景 Prometheus单实例,可用性低,可靠性低,不能存储更多数据。 解决业务问题 如:当前QKE是一个集群一个项目一个prometheus实例,那么当我一个应用分多个集群部署的时候,查询数据时就得从三个promethe…

streamlit (python构建web可视化框架)笔记

文章目录 一、安装使用streamlit二、streamlit使用1.展示和数据样式2.dataframe()生成交互表和table()方法生成静态表3.绘制折线图4.绘制地图5.一些组件slider()滑动条 checkbox()确认框 selectbox()选择器6.侧边栏7.布局分列8.多页 三、Steamlit可视化简单应用--冒泡排序可视化…

java获取当前系统时间

在Java中,可以使用以下几种方法获取当前系统时间: 方法1:使用java.util.Date类 java import java.util.Date; public class Main { public static void main(String[] args) { Date date new Date(); System.out.println("当前时间&…

短视频app开发:如何设计个性化推荐算法

短视频app的迅速崛起已经成为了移动互联网领域中的一股热潮。然而,如何设计个性化推荐算法已经成为了这个领域中的一个核心问题。在本文中,我们将深入探讨如何为短视频app开发设计个性化推荐算法,以及如何使用短视频源码来实现这一目标。 简…

类间关系和内部类和数组

Final关键词 定义Pepole类,运用了final修饰方法eat(),该方法不能被改写,但可以随类进行继承。 用final修饰的类,不能有子类。 内部成员类定义方式 外部类.成员类 对象名 new 外部类().new 内部类。 局部…

[附源码]计算机毕业设计基于SSM和UNIAPP的选课APP

项目初衷 教育要实现现代化,高质量发展,就必须拥抱互联网。在此推动下,教育APP软件的开发非常受欢迎。通过APP自主选择教育课程的专业和课程,教授讲课,课程APP可以在线合作。通过APP自主选课的方式,更能激…

深度强化学习——actor-critic算法(4)

一、本文概要: actor是策略网络,用来控制agent运动,你可以把他看作是运动员,critic是价值网络,用来给动作打分,你可以把critic看作是裁判,这节课的内容就是构造这两个神经网络,然后…

项目结束倒数2

今天,解决了,多个点的最短路问题 用的dfs,配上了floyed计算出的广源距离 难点是要记录路线,dfs记录路线就很烦 但是好在结束了,经过无数的测试,确保没啥问题(应该把) 来看看我的代码 void dfs(int b[], int x, int* sum, int last, int sums, int a[], BFS& s, Floyd_A…