Исключение в программировании - это возникновение ошибок и непредвиденных ситуаций при выполнении программы.
Исключения (ошибки при выполнении программы) могут возникать в результате:
- неправильных действий пользователя
- отсутствии необходимого ресурса на диске
- потери соединения с сервером по сети
- ошибки программирования
- неправильное использование API.
Настраивают управление исключениями для того, чтобы программа чётко знала, как поступать в ситуации появления ошибок при выполнении программы.
(чтобы предупредить и решить исключительные ситуации в программе, для того чтобы её выполнение могло быть продолжено)
В частности, механизм исключений позволяет защитить написанный код
(программный интерфейс) от неправильного использования пользователем за
счет валидации (проверки) входящих данных.
Использование исключений в Java позволяет повысить отказоустойчивость
программы за счет использования «запасных» путей, отделить логику
основного кода от кода обработки исключительных ситуаций за счет
использования блоков catch, а также дает возможность переложить
обработку исключений на пользователя нашего кода с помощью throws.
Обработка исключений в Java основана на использовании в программе следующих ключевых слов
try, catch, finally, throws
1) try – определяет (заключает под собой) блок кода, в котором может произойти исключение;
2) catch – определяет (заключает под собой) блок кода, в котором происходит обработка исключения;
(Действия при сбое, который может случиться внутри оператора try)
3) finally – определяет (заключает под собой) блок кода, который является необязательным, но при его наличии выполняется в любом случае независимо от результатов выполнения блока try.
(Блок finally часто используется для того, чтобы закрыть открытые в блоке try потоки или освободить ресурсы. Однако при написании программы не всегда возможно уследить за закрытием всех ресурсов. Для облегчения этой задачи существует конструкция try-with-resources, которая автоматически закрывает ресурсы, открытые в блоке try).
Эти ключевые слова используются для создания в программном коде специальных обрабатывающих конструкций: try{}catch, try{}catch{}finally, try{}finally{}.
На стадии разработки программы мы «ограждаем» опасные участки кода в отношении исключений с помощью блока try{}, предусматриваем «запасные» пути с помощью блока catch{}, в блоке finally{} мы пишем код, который выполняется в программе при любом исходе.
При появлении исключения в блоке try обработчик исключения ищется в
следующем за ним блоке catch. Если в catch есть обработчик данного типа
исключения – управление переходит к нему. Если нет, то JVM ищет
обработчик этого типа исключения в цепочке вызовов методов до тех пор,
пока не будет найден подходящий catch. После выполнения блока catch
управление передается в необязательный блок finally.
В случае, если подходящий блок catch не найден, JVM останавливает
выполнение программы, и выводит стек вызовов методов – stack trace,
выполнив перед этим код блока finally при его наличии.
Переменные, определенные в try не могут быть использованы в catch или finally, этот код не скомпилируется. Причина в том, что неизвестно, где именно в блоке try могло быть вызвано исключение, например, возможно, что исключение было вызвано до того, как был объявлен объект.
4) throw – используется для возбуждения исключения
5) throws – Это ключевое слово в сигнатуре метода означает, что при определенных условиях метод, может выбросить исключение
(Ключевое слово throws используется когда не планируется обрабатывать исключение в своем методе, но необходимо предупредить пользователей метода о возможных исключительных ситуациях)
Такое предупреждение является частью интерфейса метода и предоставляет право пользователю на собственный вариант реализации обработчика исключения (предоставляя написание кода по обработке исключения в Java пользователю метода.).
После throws указывается тип выбрасываемого исключения.
Типы выбрасываемых исключений:
Обычно это наследники класса Exception Java.
Поскольку Java является объектно-ориентированным языком, все исключения в Java представляют собой объекты.
При возникновении ошибки в процессе выполнения программы исполняющая
среда JVM создает объект нужного типа из иерархии исключений Java.
Иерархия исключений java:
Throwable - название класса "предка", от которого унаследовано множество возможных исключительных ситуаций.
Далее всё это множество исключительных ситуаций можно разделить на две группы:
1) Непроверяемые на стадии компиляции (неконтролируемые) (unchecked)
Это Error (исключения, унаследованные из класса Error) + RuntimeException (часть исключений - наследников
класса Exception)
RuntimeException – исключения, генерируемые JVM во время выполнения программы. Часто
причиной возникновения их являются ошибки программирования.
К этой группе относятся ситуации, при которых восстановление дальнейшей нормальной работы программы невозможно.
Это ошибки, возникающие при выполнении программы в результате сбоя
работы JVM, переполнения памяти или сбоя системы. Обычно они
свидетельствуют о серьезных проблемах, устранить которые программными
средствами невозможно, такими как деление на 0, нулевой указатель и т.п.
Список непроверяемых исключений:
ArithmeticException - арифметическая ошибка, например, деление на ноль
ArrayIndexOutOfBoundsException - выход индекса за границу массива
ArrayStoreException - присваивание элементу массива объекта несовместимого типа
ClassCastException - неверное приведение
EnumConstantNotPresentException - попытка использования неопределённого значения перечисления
IllegalArgumentException - неверный аргумент при вызове метода
IllegalMonitorStateException - неверная операция мониторинга
IllegalStateException - некорректное состояние приложения
IllegalThreadStateException - запрашиваемая операция несовместима с текущим потоком
IndexOutofBoundsException - тип индекса вышел за допустимые пределы
NegativeArraySizeException - создан массив отрицательного размера
NullPointerException - неверное использование пустой ссылки
NullPointerException (оно же NPE) - это исключение, которое
выбрасывается каждый раз, когда вы обращаетесь к методу или полю объекта
по ссылке, которая равна null.
NumberFormatException - неверное преобразование строки в числовой формат
SecurityException - попытка нарушения безопасности
StringIndexOutOfBounds - попытка использования индекса за пределами строки
TypeNotPresentException - тип не найден
UnsupportedOperationException - обнаружена неподдерживаемая операция
2) Проверяемые на стадии компиляции (предвидимые еще на стадии написания программы) (контролируемые) (checked)
Это Exception (кроме RuntimeException)
Основная часть работы разработчика на Java при работе с исключениями – обработка таких ситуаций: проверяемые исключения должны быть явно пойманы в теле метода или объявлены в секции throws метода.
Для проверяемых исключений ожидается, что другие разработчики, использующие API, будут знать,
как обращаться с исключениями.
Список проверяемых системных исключений, которые можно включать в список throws:
ClassNotFoundException - класс не найден
CloneNotSupportedException - попытка клонировать объект, который не реализует интерфейс Cloneable
IllegalAccessException - запрещен доступ к классу
InstantiationException - попытка создать объект абстрактного класса или интерфейса
InterruptedException - поток прерван другим потоком
NoSuchFieldException - запрашиваемое поле не существует
NoSuchMethodException - запрашиваемый метод не существует
ReflectiveOperationException - исключение, связанное с рефлексией
Пример использования ключевых слов в java-программе:
public String input() throws MyException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String s = null;
try {
s = reader.readLine();
} catch (IOException e) {
System.out.println(e.getMessage());
} finally {
try {
reader.close();
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
if (s.equals("")) {
throw new MyException("String can not be empty!");
}
return s;
}
Этот же пример с помощью try-with-resources
:
public String input() throws MyException {
String s = null;
try(BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))){
s = reader.readLine();
} catch (IOException e) {
System.out.println(e.getMessage());
}
if (s.equals("")){
throw new MyException ("String can not be empty!");
}
return s;
}