Java 异常|Java Exceptions
本文是对以下内容的分析:Java异常设计,Java异常可以告诉什么,以及如何使用Java异常。
Java Exceptions
Java Exception 是为处理异常应用程序行为而创建的类。在本文中,我将解释如何使用 Java Exception 类以及如何在考虑现有 Java Exceptions 设计的情况下创建异常结构。Java 异常概念是 Java 中的重要里程碑之一,每个开发人员都必须知道它。
Java 异常结构的信息量比你想象的要多
Java 异常的结构非常有用,可以告诉开发人员一组重要的事情(如果开发人员正确使用此结构)。所以,在这里,您可以看到基本结构:

可以捕获所有可能情况的主要父级是 Throwable,它有 2 个子级:错误和异常。
Java错误
Java Error case 代表异常情况。一旦出现错误,应用程序可能会关闭。
Java异常
与错误不同,Java 异常有机会从问题中恢复应用程序并尝试保持应用程序运行。异常也分为两组:

异常由运行时和非运行时异常表示,也称为检查异常。此分类与错误异常非常相似,但在该分类中,已检查异常在恢复方面更为乐观。
检查和未检查异常
在 Java 中,有两种类型的异常。检查 异常迫使开发人员创建处理程序异常或重新抛出它们。如果重新抛出已检查的异常,则 java 函数必须在其签名中声明它。Unchecked 异常 unline checked 不需要任何处理。这样的设计意味着无法处理未经检查的异常,并且注定会被抛出到顶级父级。

Java 中的异常处理
有两种方法可以处理抛出的异常:在当前方法中处理它或者只是重新抛出它。没有比这更好的方法了。您可能有一个父处理程序或以某种方式处理它,例如制作重试逻辑。

检查,运行时,错误;那又怎么样?
介绍完之后,我们可以将所有异常分为 3 组:Checked、Runtime 和 Error。主要思想是,他们每个人都会陷入不同的情况。最乐观的是 Checked 异常。运行时将属于恢复机会很小 的情况 。而且,最悲观的是Error。

检查,运行时,错误;所以呢?
了解异常类的类型后,我们可能会 回答下一个问题:
- 情况有多糟糕以及问题的原因是什么。
- 如何解决问题。
- 我们需要重启JVM吗?
- 我们需要重写代码吗?
知道异常类,我们可以预测可能出错的地方。考虑潜在的原因,我们可以假设问题的原因是什么以及如何解决它。让我们回顾一下最流行的场景,看看这些异常可以告诉我们什么。在接下来的段落中,我们将回顾著名的异常并调查潜在的代码是什么。在我们的调查中,我们假设应用程序足够稳定并且开发阶段已经完成和测试。
调查错误异常
我们从最悲观的案例或我们的丑男开始。是错误 真的有那么丑吗?让我们来看看最流行的 Java 错误:
|
潜在原因 |
原因的可能性有多大 |
怎么修 |
需要重写代码吗? |
需要重启JVM吗? |
|
|---|---|---|---|---|---|
|
内存不足 |
应用程序吃掉了所有内存 |
高的 |
增加堆内存大小 |
不 |
是的 |
|
内存泄漏 |
低的 |
查找内存泄漏并修复 |
是的 |
是的 |
|
|
堆栈溢出 |
堆栈内存不足 |
高的 |
增加堆栈内存大小 |
不 |
是的 |
|
无限递归 |
低的 |
设置递归调用的限制 |
是的 |
是的 |
|
|
NoClassDefFoundError |
缺少依赖 |
高的 |
添加依赖或修复依赖配置 |
不 |
是的 |
|
初始化期间加载类失败 |
低的 |
更改初始化过程 |
是的 |
是的 |
因此,在大多数情况下,您需要做的就是更改 JVM 配置或添加缺少的依赖项。仍然存在需要更改代码的情况,但它们不太可能在每种情况下应用更改。

调查检查异常
对于受检异常,我们期望有机会恢复问题;例如,再试一次。在这一部分,我们回顾最著名的 Checked 异常。提供的例外可能是彼此的父级,但是,在这里,我只列出最流行的案例,而不管它们的关系如何:
|
潜在原因 |
原因的可能性有多大 |
怎么修 |
需要重写代码吗? |
需要重启吗? |
|
|---|---|---|---|---|---|
|
文件未找到异常 |
该文件不存在 |
高的 |
创建文件 |
不 |
不 |
|
应用程序调用错误的路径 |
低的 |
修复错误的路径生成 |
是的 |
是的 |
|
|
IO异常 |
访问资源无效 |
高的 |
让资源再次可用 |
不 |
不 |
|
类未找到异常 |
该类未添加依赖项 |
高的 |
添加缺少的依赖项 |
不 |
是的 |
|
实现调用了错误的类 |
中等的 |
更改类调用 |
是的 |
是的 |
|
|
异常 |
架构与查询不匹配 |
高的 |
将缺失的脚本应用到数据库 |
不 |
不 |
|
查询错误 |
低的 |
更改查询 |
是的 |
是的 |
|
|
拒绝连接 |
高的 |
打开数据库,更改端口 |
不 |
不 |
|
|
中断异常 |
依赖线程通知中断(锁释放,另一个线程完成操作) |
高的 |
没有必要修复它;这是一种通知相关线程中事件的方法 |
不 |
不 |
|
另一个线程中断并使用中断通知相关 |
中等的 |
修复另一个线程中出现的问题(可以是任何东西) |
是的 |
是的 |
|
|
套接字异常 |
端口被占用 |
高的 |
打开/释放端口 |
不 |
不 |
|
服务器断开连接 |
高的 |
检查网络连接或进行 |
不 |
不 |
好吧,有很多例外,但是,正如我所承诺的,我把最流行的例外放在这里。那么,这张表说明了什么?如果我们查看最可能的原因,我们会发现其中的大多数 不仅不需要任何代码更改,甚至不需要重新启动应用程序。所以,显然,Checked 异常值得成为好人。

调查运行时异常
最常见也是个人最悲观的例外:运行时。Checked 和 Error 异常错误不会导致任何代码更改。但是,在大多数情况下,运行时异常会突出代码中的实际问题,如果不重写代码就无法修复这些问题。让我们通过查看最流行的运行时异常来找出原因:
|
潜在原因 |
原因的可能性有多大 |
怎么修 |
需要重写代码吗? |
需要重启吗? |
|
|---|---|---|---|---|---|
|
空指针异常 |
预期的不可为空的对象为空 |
高的 |
调用前添加验证层 |
是的 |
是的 |
|
某些资源不可用并返回空数据 |
中等的 |
调用前添加验证层 |
是的 |
是的 |
|
|
并发修改异常 |
迭代期间集合已更改 |
高的 |
分别进行集合迭代和修改 |
是的 |
是的 |
|
集合在迭代期间已从另一个线程更改 |
高的 |
为集合添加同步 |
是的 |
是的 |
|
|
非法参数异常 |
传递的参数无效 |
高的 |
在传递参数之前添加验证 |
是的 |
是的 |
|
数字格式异常 |
传递的参数格式错误或符号错误 |
高的 |
在传递数据之前添加格式或删除不可见符号 |
是的 |
是的 |
|
ArrayIndexOutOfBoundsException |
指令试图通过不存在的索引访问单元格 |
高的 |
将访问逻辑更改为正确的逻辑 |
是的 |
是的 |
|
无此类元素异常 |
当指针已经改变位置时访问元素 |
高的 |
将访问逻辑更改为正确的逻辑 |
是的 |
是的 |
|
集合在迭代过程中被修改 |
高的 |
为集合添加同步 |
是的 |
是的 |
一个例子可能给人的印象是任何运行时异常都会导致应用程序失败。在大多数情况下,这是正确的,因为不更改代码就无法恢复应用程序。最终,运行时异常是我们的坏人,它会导致新的代码更改、开发人员的压力和业务损失。

一点批评
在这次审查期间,我们做出了一个重大假设:代码已准备好投入生产并经过充分测试。但是,在实践中,这是很难实现的。所以,我们所做的结论并不是100%可靠,但是代码越稳定,结果就越真实。
检查异常和代码污染
根据检查异常,设计开发人员必须使所有可恢复的异常可检查。因此,每次调用带有已检查异常签名的方法都会为 Try Catch 结构添加 3-4 行。这种方法使代码变得丑陋且可读性较差。就个人而言,我更喜欢使用运行时异常。即使在设计库的情况下,您仍然可以在方法签名中保留运行时异常,并在 API 中添加一些注释。在这种情况下,您的 API 用户将能够决定如何处理它。

更多推荐




所有评论(0)