Java 异常机制

Java
319
0
0
2023-05-27

【注】本文译自:

Java Exception

Java Exception 是为处理异常应用程序行为而创建的类。在本文中,我将解释如何使用 Java Exception 类以及如何在考虑现有 Java Exceptions 设计的情况下创建异常结构。Java 异常概念是 Java 中的重要里程碑之一,每个开发人员都 必须 了解它。

Java 异常结构比你想象的要有用

Java 异常的结构非常有用,可以告诉开发人员一组重要的事情(如果开发人员正确使用此结构)。所以,在这里,您可以看到基本结构:

Java 异常机制

可以捕获所有可能情况的主要父类是 Throwable,它有 2 个子类:Error 和 Exception。

Java Error

Java Error 代表异常情况。一旦出现错误,应用程序可能会关闭。

Java Exception

与错误不同,Java 异常有机会从问题中恢复应用程序,并尝试保持应用程序运行。异常也分为两类:

Java 异常机制

异常由运行时和非运行时异常表示,也称为已检异常。此分类与错误异常非常相似,但在该分类中,已检异常在恢复方面更为乐观。

已检和未检异常

在 Java 中,有两种类型的异常。 已检 异常迫使开发人员创建处理程序异常或重新抛出它们。如果重新抛出已检查的异常,则 java 函数必须在其签名中声明它。 未检 异常 unline checked 不需要任何处理。 这样的设计意味着无法处理未经检查的异常,并且注定会被抛出到顶级父类。

Java 异常机制

Error 异常调查

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

Java 异常机制

好的、坏的、丑的

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

Java 异常机制

Checked, Runtime, Error … 然后呢?

了解异常类的类型后,我们 可能会 回答下一个问题:

  • 情况有多糟糕,问题的原因是什么。
  • 如何解决这个问题。
  • 我们需要重启 JVM 吗?
  • 我们需要重写代码吗?

知道异常类,我们可以预测可能出错的地方。考虑潜在的原因,我们可以假设问题的原因是什么以及如何解决它。让我们回顾一下最流行的场景,看看这些异常可以告诉我们什么。在接下来的段落中,我们将回顾著名的异常并调查潜在的代码是什么。在我们的调查中,我们假设应用程序足够稳定并且开发阶段已经完成和测试。

Error 异常调查

我们从最悲观的案例或我们的丑男开始。 Error 真的有那么丑吗? 让我们来看看最常见的 Java 错误:

潜在原因

发生机率

如何修复

是否需要重写代码?

是否需要重启 JVM?

OutOfMemory

应用程序吃掉了所有内存

增加堆内存大小


内存泄漏

查找内存泄漏并修复

StackOverFlow

堆栈内存不足

增加堆栈内存大小


无限递归

设置递归调用的限制

NoClassDefFoundError

缺少依赖

添加依赖或修复依赖配置


初始化期间加载类失败

更改初始化过程

因此,在大多数情况下,您需要做的就是更改 JVM 配置或添加缺少的依赖项。仍然存在需要更改代码的情况,但它们不太可能在每种情况下应用更改。

Java 异常机制

对于受检异常,我们期望有机会恢复问题;例如,再试一次。在这一部分,我们回顾最著名的已检异常。提供的例外可能是彼此的父类,但是,在这里,我只列出最常见的案例,而不关心它们的关系:

潜在原因

发生机率

如何修复

是否需要重写代码?

是否需要重启 JVM?

FileNotFoundException

文件不存在

创建文件


应用程序调用错误的路径

修复错误的路径生成

IOException

访问资源无效

让资源再次可用

ClassNotFoundException

该类未添加依赖项

添加缺少的依赖项


实现调用了错误的类

更改类调用

SqlException

模式与查询不匹配

将缺失的脚本应用到数据库


查询错误

更改查询


拒绝连接

打开数据库,更改端口

Interrupted Exception

依赖线程通知中断(锁释放,另一个线程完成操作)

没有必要修复它; 这是一种通知相关线程中事件的方法


另一个线程中断并使用中断通知相关

修复另一个线程中出现的问题(可以是任何东西)

Socket Exception

端口被占用

打开/释放端口


服务器断开连接

检查网络连接

好吧,有很多异常,但是,正如我所承诺的,我把最常见的异常放在这里。那么,这张表说明了什么?如果我们查看最可能的原因,我们会发现其中的 大多数 不仅不需要任何代码更改,甚至不需要重新启动应用程序。所以,显然,已检异常应该是好人。

Java 异常机制

Runtime 异常调查

最常见也是个人最悲观的例外:运行时。Checked 和 Error 异常错误不会导致任何代码更改。但是,在大多数情况下,运行时异常突出了代码中的真正问题,如果不重写代码就无法修复这些问题。让我们通过查看最流行的运行时异常来找出原因:

潜在原因

发生机率

如何修复

是否需要重写代码?

是否需要重启 JVM?

NullPointerException

预期的不可为空的对象为空

调用前添加验证层


某些资源不可用并返回空数据

调用前添加验证层

ConcurrentModificationException

迭代期间集合已更改

分别进行集合迭代和修改


集合在迭代期间已从另一个线程更改

为集合添加同步

IlliegalArgumentException

传递的参数无效

在传递参数之前添加验证

NumberFormatException

传递的参数格式错误或符号错误

在传递数据之前添加格式或删除不可见符号

ArrayIndexOutOfBoundsException

指令试图通过不存在的索引访问单元格

将访问逻辑更改为正确的逻辑

NoSuchElementException

当指针已经改变位置时访问元素

将访问逻辑更改为正确的逻辑


集合在迭代过程中被修改

为集合添加同步

一个例子可能给人的印象是任何运行时异常都会导致应用程序失败。在大多数情况下,这是正确的,因为不更改代码就无法恢复应用程序。最终,运行时异常是我们的坏人,它会导致新的代码更改、开发人员的压力和业务损失。

些许批评

在这次审查期间,我们做出了一个重大假设:代码已准备好投入生产并经过充分测试。但是,在实践中,这很难实现。所以,我们所做的结论并不是100% 可靠,但是代码越稳定,结果就越真实。

已检异常和代码污染

根据已检查异常,设计开发人员必须使所有可恢复的异常都是可检查的。因此,每次调用带有已检查异常签名的方法都会为 Try Catch 结构添加 3-4 行。这种方法使代码变得丑陋且可读性较差。就个人而言,我更喜欢使用运行时异常。即使在设计库的情况下,您仍然可以在方法签名中保留运行时异常,并在 API 中添加一些注释。在这种情况下,您的 API 用户将能够决定如何处理它。