Перейти к основному содержимому

Это плохая практика, чтобы поймать Throwable?

· 3 мин. чтения

1. Обзор

В этом уроке мы рассмотрим последствия перехвата Throwable `` .

2. Метательный класс

В документации по Java класс Throwable определяется как « суперкласс всех ошибок и исключений в языке Java ».

Давайте посмотрим на иерархию класса Throwable :

./565d35cf8c078a0d68e6df2a40646d8d.png

Класс Throwable имеет два прямых подкласса, а именно классы Error и Exception .

Error и его подклассы являются непроверенными исключениями, в то время как подклассы Exception могут быть либо проверенными, либо непроверенными исключениями .

Давайте рассмотрим типы ситуаций, в которых программа может столкнуться при сбое.

3. Восстановимые ситуации

Существуют ситуации, когда восстановление, как правило, возможно и может быть обработано либо проверенными, либо непроверенными подклассами класса Exception .

Например, программа может захотеть использовать файл, который не существует в указанном месте, в результате чего будет выдано проверенное исключение FileNotFoundException .

Другим примером является попытка программы получить доступ к системному ресурсу, не имея на это разрешения, в результате чего возникает непроверенное исключение AccessControl Exception .

Согласно документации Java, класс Exception «указывает условия, которые разумное приложение может захотеть отловить ».

4. Неисправимые ситуации

Бывают случаи, когда программа может попасть в состояние, когда восстановление невозможно в случае сбоя. Типичными примерами этого являются переполнение стека или нехватка памяти JVM.

В этих ситуациях JVM генерирует StackOverflowError и OutOfMemoryError соответственно. Как следует из их названий, это подклассы класса Error .

Согласно документации Java, класс Error «указывает на серьезные проблемы, которые разумное приложение не должно пытаться отловить ».

5. Пример исправимых и неисправимых ситуаций

Предположим, что у нас есть API, который позволяет вызывающим сторонам добавлять уникальные идентификаторы в какое-то хранилище с помощью метода addIDsToStorage :

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 ...
}

При вызове addIDsToStorage может возникнуть несколько потенциальных точек отказа :

  • CapacityException — проверенный подкласс Exception при передаче значения емкости менее 1.
  • NullPointerException — непроверенный подкласс Exception , если вместо экземпляра Set<String> указано нулевое значение хранилища . ``
  • OutOfMemoryError — непроверяемый подкласс Error , если JVM не хватает памяти до выхода из цикла while .

Ситуации CapacityException и NullPointerException являются сбоями, после которых программа может восстановиться, но OutOfMemoryError является неустранимой ошибкой.

6. Ловля бросаемого

Предположим, что пользователь API перехватывает только Throwable в try-catch при вызове addIDsToStorage :

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

Это означает, что вызывающий код одинаково реагирует на исправимые и неисправимые ситуации.

Общее правило обработки исключений заключается в том, что блок try-catch должен быть как можно более конкретным при перехвате исключений. То есть нужно избегать всеохватывающего сценария .

Перехват Throwable в нашем случае нарушает это общее правило. Чтобы реагировать на восстанавливаемые и неисправимые ситуации отдельно, вызывающий код должен проверять экземпляр объекта Throwable внутри блока catch .

Лучше использовать особый подход к обработке исключений и избегать попыток справиться с неисправимыми ситуациями .

7. Заключение

В этой статье мы рассмотрели последствия перехвата Throwable в блоке try-catch .

Как всегда, полный исходный код примера доступен на Github .