Catch Me If You ... Can't Do Otherwise

The following text is a partial translation of the original English article, performed by ChatGPT (gpt-3.5-turbo) and this Jekyll plugin:

我不知道这是一种反模式还是一种常见且非常流行的错误,但我到处都看到它,必须写下来。我说的是捕获异常而不重新抛出。我说的是类似于这种Java代码:

请注意:我对这段代码没有任何意见。

这被称为异常链,并且是一个完全有效的构造。

那么,捕获异常并记录下来有什么问题呢?让我们先试着从更大的视角来看。我们正在讨论面向对象的编程—这意味着我们正在处理对象。以下是一个对象(确切地说是它的类)的外观:

这是我使用这个类的方式:

看起来不错,对吧?当我调用send(1)时,我不需要担心IOException。它将在内部处理,如果发生异常,堆栈跟踪将被记录。但这是一种完全错误的思维方式,它继承自没有异常的语言,比如C。

异常的发明是为了通过将整个错误处理代码从主逻辑中移开来简化我们的设计。此外,我们不仅仅是将其移开,还将其集中在一个地方-在main()方法中,整个应用程序的入口点。

异常的主要目的是收集关于错误的尽可能多的信息,并将其传递到最高级别,用户可以对其进行处理。异常链还进一步帮助我们通过允许在传递过程中扩展该信息。我们基本上是每次捕获并重新抛出时,都将我们的气泡(异常)放入一个更大的气泡中。当它到达表面时,有许多气泡,每个气泡都保留在另一个气泡内部,就像俄罗斯套娃一样。原始异常是最小的气泡。

当您捕获异常而不重新抛出时,您基本上是将气泡弹出。其中的所有内容,包括原始异常和所有其他包含其中信息的气泡,都在您手中。您不让我看到它们。您以某种方式使用它们,但我不知道如何使用。您在幕后做一些事情,隐藏了潜在重要的信息。

如果您向我隐藏这些信息,我无法向我的用户承诺在发生问题时诚实地向他报告。我简直无法再相信您的send()方法,而我的用户也不会相信我。

通过捕获异常而不重新抛出它们,您基本上破坏了对象之间的信任链。

我的建议是尽可能少地捕获异常,并且每次捕获时都重新抛出。

不幸的是,Java的设计在许多地方违背了这个原则。例如,Java有已检查和未检查的异常,而在我看来,应该只有已检查的异常(必须捕获或声明为可抛出的异常)。此外,Java允许在单个方法中声明多个可抛出的异常类型-这是另一个错误;只声明一种类型。此外,还有一个位于层次结构顶部的通用Exception类,我认为也是错误的。除此之外,一些内置类不允许抛出任何已检查的异常,例如Runnable.run()。Java中的异常还有许多其他问题。

但请尽量牢记这个原则,您的代码将更加清晰:只有在没有其他选择时才使用catch

附:以下是类应该如何看起来的:

Translated by ChatGPT gpt-3.5-turbo/42 on 2023-12-27 at 05:20

sixnines availability badge   GitHub stars