1. Обзор
В этом уроке мы рассмотрим последствия перехвата
Throwable `` .
2. Метательный
класс
В документации по Java класс Throwable
определяется как « суперкласс всех ошибок и исключений в языке Java ».
Давайте посмотрим на иерархию класса Throwable
:
Класс 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 .