Is It a Bad Practice to Catch Throwable? – 捕捉可抛物是一种不好的做法吗?

最后修改: 2019年 11月 15日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’ll look at the implications of catching Throwable.

在本教程中,我们将看看捕获Throwable含义。

2. The Throwable Class

2.可抛物

In the Java documentation, the Throwable class is defined as “the super-class of all errors and exceptions in the Java language“.

在Java文档中,Throwable类被定义为”Java语言中所有错误和异常的超类“。

Let’s look at the hierarchy of the Throwable class:

我们来看看Throwable类的层次结构。

The Throwable class has two direct sub-classes – namely, the Error and Exception classes.

Throwable类有两个直接的子类,即ErrorException类。

Error and its sub-classes are unchecked exceptions, while the sub-classes of Exception can be either checked or unchecked exceptions.

Error及其子类是未检查的异常,而Exception的子类可以是已检查或未检查的异常

Let’s look at the types of situations a program can experience when it fails.

让我们看看一个程序在失败时可能遇到的各类情况。

3. Recoverable Situations

3.可恢复的情况

There are situations where recovery is generally possible and can be handled with either checked or unchecked sub-classes of the Exception class.

有些情况下,恢复一般是可能的,可以用Exception类的检查或不检查的子类来处理。

For example, a program might want to use a file that happens to not exist at the specified location, resulting in a checked FileNotFoundException being thrown.

例如,一个程序可能想使用一个文件,但该文件恰好不存在于指定的位置,从而导致一个被检查的FileNotFoundException被抛出。

Another example is the program attempting to access a system resource without having permission to do that, resulting in an unchecked AccessControlException being thrown.

另一个例子是,程序在没有权限的情况下试图访问系统资源,结果是抛出一个未检查的AccessControlException

As per the Java documentation, the Exception class “indicates conditions that a reasonable application might want to catch“.

根据Java文档,Exception 类 “表示一个合理的应用程序可能想要捕捉的条件“。

4. Irrecoverable Situations

4.无法恢复的情况

There are cases where a program can get in a state where recovery is impossible in an event of a failure. Common examples of this are when a stack overflow occurs or the JVM runs out of memory.

在有些情况下,程序可能会处于一种状态,在发生故障时不可能恢复。常见的例子是当堆栈溢出或JVM内存耗尽时。

In these situations, the JVM throws StackOverflowError and OutOfMemoryError, respectively. As suggested by their names, these are sub-classes of the Error class.

在这些情况下,JVM会分别抛出StackOverflowErrorOutOfMemoryError。正如它们的名字所暗示的,这些是Error类的子类。

According to the Java documentation, the Error class “indicates serious problems that a reasonable application should not try to catch“.

根据Java文档,Error 类 “表示一个合理的应用程序不应该尝试捕捉的严重问题“。

5. Example of Recoverable and Irrecoverable Situations

5.可恢复和不可恢复情况的例子

Let’s assume that we have an API that allows callers to add unique IDs to some storage facility using the addIDsToStorage method:

让我们假设我们有一个API,允许调用者使用addIDsToStorage方法向一些存储设施添加唯一的ID。

class StorageAPI {

    public void addIDsToStorage(int capacity, Set<String> storage) throws CapacityException {
        if (capacity < 1) {
            throw new CapacityException("Capacity of less than 1 is not allowed");
        }
        int count = 0;
        while (count < capacity) {
            storage.add(UUID.randomUUID().toString());
            count++;
        }
    }

    // other methods go here ...
}

Several potential failure points can occur when invoking addIDsToStorage:

调用addIDsToStorage时,可能会出现几个潜在的故障点。

  • CapacityException – A checked sub-class of Exception when passing a capacity value of less than 1
  • NullPointerException – An unchecked sub-class of Exception if a null storage value is provided instead of an instance of Set<String>
  • OutOfMemoryError – An unchecked sub-class of Error if the JVM runs out of memory before exiting the while loop

The CapacityException and NullPointerException situations are failures the program can recover from, but the OutOfMemoryError is an irrecoverable one.

CapacityExceptionNullPointerException情况是程序可以恢复的故障,但OutOfMemoryError是一个无法恢复的故障。

6. Catching Throwable

6.捕获可抛物

Let’s assume the user of the API only catches Throwable in the try-catch when calling addIDsToStorage:

我们假设API的用户在调用addIDsToStorage时,只在try-catch中捕捉到Throwable

public void add(StorageAPI api, int capacity, Set<String> storage) {
    try {
        api.addIDsToStorage(capacity, storage);
    } catch (Throwable throwable) {
        // do something here
    }
}

This means that the calling code is reacting to recoverable and irrecoverable situations in the same way.

这意味着调用代码以同样的方式对可恢复和不可恢复的情况做出反应。

The general rule in handling exceptions is that the try-catch block must be as specific as possible in catching exceptions. That is, a catch-all scenario must be avoided.

处理异常的一般规则是,try-catch块在捕获异常时必须尽可能地具体。也就是说,必须避免万能的情况

Catching Throwable in our case violates this general rule. To react to recoverable and irrecoverable situations separately, the calling code would have to inspect the instance of the Throwable object inside the catch block.

在我们的案例中捕获Throwable违反了这一一般规则。为了对可恢复和不可恢复的情况分别做出反应,调用代码将不得不在catch块中检查Throwable对象的实例。

The better way would be to use a specific approach in handling exceptions and to avoid trying to deal with irrecoverable situations.

更好的方法是在处理异常时使用特定的方法,避免试图处理不可恢复的情况

7. Conclusion

7.结语

In this article, we looked at the implications of catching Throwable in a try-catch block.

在这篇文章中,我们研究了在try-catch块中捕获Throwable的意义。

As always, the full source code of the example is available over on Github.

一如既往,该示例的完整源代码可在Github上获取over