Исключения в Java
Классификация исключений
- java.lang.Throwable — базовый класс для всех исключений;
- Исключительные ситуации в пользовательском коде:
- java.lang.Exception — базовый класс для проверяемых (checked) исключений, соответствующих ошибкам программной логики;
- java.lang.RuntimeException — базовый класс для непроверяемых (unchecked) исключений, соответствующих ошибкам программной логики:
- java.lang.NullPointerException;
- java.lang.ArrayIndexOutOfBoundsException;
- java.lang.ArithmeticException;
- …
- Исключительные ситуации в JVM:
- java.lang.Error — базовый класс для исключений, соответствующих ошибкам виртуальной машины:
- java.lang.OutOfMemoryError;
- java.lang.NoClassDefFoundError;
- java.lang.VerifyError;
- …
Собственное исключение
public class CalculatorException extends RuntimeException { public CalculatorException(String message) { super(message); } public CalculatorException(String message, Throwable cause) { super(message, cause); } }
public class CalculatorImpl implements Calculator { @Override public double calculate(String expr) { // ... throw new CalculatorException( "Unsupported operator found"); // ... } }
Перехват исключения: try-catch
for (;;) { System.out.print("Enter expression: "); String expr = readUserInput(); if (expr == null || " exit ".equalsIgnoreCase(expr)) { break; } try { double result = calculator.calculate(expr); System.out.println("Result: " + result); } catch (CalculatorException e) { System.out.print("Bad expression: " + e.getMessage()); System.out.print("Please try again: "); } }
Перехват нескольких исключений
try { // ... } catch (FirstException e) { e.printStackTrace(); } catch (SecondException e) { e.printStackTrace(); } // since Java 7 can be replaced with : try { // ... } catch (FirstException | SecondException e) { e.printStackTrace(); }
finally
finally не является обработчиком исключения, т.е. если из блока try вылетело исключение, то после отработки блока finally это исключение полетит дальше.
InputStream is = new FileInputStream("a.txt");
try {
readFromInputStream(is);
} finally {
try {
is.close();
} catch (IOException e) {
// ignore
}
}
Исключение из close() здесь явно отлавливается и игнорируется, чтобы не перебивать исходную ошибку.
try с ресурсами (вместо исключений в finally)
try (InputStream is = new FileInputStream("a.txt")) {
readFromInputSteam(is);
}
В круглых скобках выделяются ресурсы с которыми будет работать этот блок. Их может быть несколько, в таком случае они перечисляются через точку с запятой. Гарантируется, что при выходе из блока все ресурсы будут освобождены, точнее, что на каждом из ресурсов будет вызван метод close(). Ресурс это любой объект реализующий интерфейс java.lang.AutoCloseable.
package java.lang; public interface AutoCloseable { void close() throws Exception; }
Аналогично блоку finally это случится при любом раскладе, было исключение или не было. Здесь исключение из close() не перебьет собой исходное исключение, а будет добавлено в него в качестве заглушенного. То что происходит в блоке try с ресурсами можно иллюстрировать следующим фрагментом кода, который не передает все нюансы, но демонстрирует идею.
InputStream is = new FileInputStream("a.txt");
try {
readFromInputStream(is);
} catch (Throwable t) {
try {
is.close();
} catch (Throwable t2) {
t.addSuppressed(t2);
}
throw t;
}
is.close();
Классы исключений
Последнее обновление: 23.04.2018
Базовым классом для всех исключений является класс Throwable. От него уже наследуются два класса: Error
и Exception. Все остальные классы являются производными от этих двух классов.
Класс Error описывает внутренние ошибки в исполняющей среде Java. Программист имеет очень ограниченные возможности для обработки подобных ошибок.
Собственно исключения наследуются от класса Exception. Среди этих исключений следует выделить класс RuntimeException.
RuntimeException является базовым классом для так называемой группы непроверяемых исключений (unchecked exceptions) —
компилятор не проверяет факт обработки таких исключений и их можно не указывать вместе с оператором throws в объявлении метода.
Такие исключения являются следствием ошибок разработчика, например, неверное преобразование типов или выход за пределы массива.
Некоторые из классов непроверяемых исключений:
-
ArithmeticException: исключение, возникающее при делении на ноль
-
IndexOutOfBoundException: индекс вне границ массива
-
IllegalArgumentException: использование неверного аргумента при вызове метода
-
NullPointerException: использование пустой ссылки
-
NumberFormatException: ошибка преобразования строки в число
Все остальные классы, образованные от класса Exception, называются проверяемыми исключениями (checked exceptions).
Некоторые из классов проверяемых исключений:
-
CloneNotSupportedException: класс, для объекта которого вызывается клонирование, не реализует интерфейс Cloneable
-
InterruptedException: поток прерван другим потоком
-
ClassNotFoundException: невозможно найти класс
Подобные исключения обрабатываются с помощью конструкции try..catch. Либо можно передать обработку методу, который будет вызывать данный метод,
указав исключения после оператора throws:
public Person clone() throws CloneNotSupportedException{
Person p = (Person) super.clone();
return p;
}
В итоге получается следующая иерархия исключений:

Поскольку все классы исключений наследуются от класса Exception, то все они наследуют ряд его методов, которые позволяют получить информацию о
характере исключения. Среди этих методов отметим наиболее важные:
-
Метод getMessage() возвращает сообщение об исключении
-
Метод getStackTrace() возвращает массив, содержащий трассировку стека исключения
-
Метод printStackTrace() отображает трассировку стека
Например:
try{
int x = 6/0;
}
catch(Exception ex){
ex.printStackTrace();
}
% Throwable
Класс: java.lang.Throwable
Описание
Throwable — базовый класс всех исключений Java. В инструкциях throw и catch можно использовать только
объекты класса Throwable и его подклассов.
Объект-исключение содержит в себе текстовое сообщение, говорящее о причине ошибки, трассировку стека вызовов на момент
создания, а также, возможно, причину (cause) — исключение более низкого уровня, завёрнутое в данное исключение.
Иерархия исключений
Все исключения в Java делятся на две большие и неравные группы. Меньшая группа наследует от класса Error и обозначает
серьёзные низкоуровневые ошибки, после которых продолжение выполнения программы обычно бессмысленно. Большая группа
наследует от класса Exception и отвечает за обычные нештатные ситуации, которые могут возникнуть в ходе выполнения
программы.
Теоретически язык Java не запрещает определить свой подкласс класса Throwable, не производный ни от Error, ни от
Exception. Компилятор будет рассматривать такую неведому зверушку как обычное проверяемое исключение (см. ниже), но
на практике так никто не поступает, да и необходимости в этом нет.
Проверяемые и непроверяемые исключения
Классы Error и RuntimeException занимают особое положение в иерархии исключений. Эти классы, а также все производные
от них, являются непроверяемыми исключениями (unchecked exceptions). Все остальные исключения являются проверяемыми
(checked exceptions). На диаграмме классов выше непроверяемые исключения выделены голубым, а проверяемые
— зелёным.
Метод, внутри которого может быть выброшено проверяемое исключение, должен либо обработать его в блоке catch, либо
передать выше и явно сказать об этом в объявлении с помощью ключевого слова throws (и тогда разбираться с ним будут
уже где-то выше). На непроверяемые исключения компилятор не налагает таких требований.
void throwsIOException() throws IOException { if (MoonPhase.getCurrent() == MoonPhase.FULL) { // непроверяемое исключение; можно обработать, но компилятор не заставляет throw new IllegalStateException(); } else { // проверяемое исключение throw new IOException(); } } void handlesIOException() { try { throwsIOException(); } catch (IOException e) { e.printStackTrace(); } }
В стандартной библиотеке есть одно нарушение этого правила. Статический метод
Class.newInstanceпередаёт во внешний
код любые исключения, в том числе проверяемые, что позволяет обойти проверки времени компиляции:public class Thrower { private Thrower () throws IOException { throw new IOException(); } public static void main(String[] args) { try { Thrower t = Thrower.class.newInstance(); } catch (IllegalAccessException | InstantiationException e) { // Ну хотя бы эти нужно обрабатывать, но уже поздно } } }Здесь
mainупадёт поIOException, хотя обычно компилятор заставил бы нас объявить его какthrows IOException.
Мораль в том, что при использовании рефлексии всегда нужно быть осторожными, потому что она предоставляет внеязыковой
механизм манипуляции классами и методами.
Ошибки (Error)
Исключения, производные от класса Error, являются непроверяемыми и обладают объединяющими свойствами:
- Они сигнализируют о серьёзных ошибках низкого уровня, после которых восстановление обычно невозможно.
- Многие из них (в частности,
OutOfMemoryError,LinkageErrorиThreadDeath) могут возникнуть практически в любом
месте программы, поэтому настраиваться на них заранее обычно бессмысленно. Кроме того, место, где выбрасывается
исключение, обычно не связано с местом логического возникновения нижележащей проблемы.
Ловить и обрабатывать исключения, производные от Error, обычно не следует. Они выбрасываются затем, чтобы как можно
быстрее дать потоку завершиться аварийно, выполнив при этом все блоки finally при раскрутке стека.
Вот некоторые наиболее распространённые исключения типа Error:
StackOverflowError
: Переполнение стека вызовов. Обычно это указывает на бесконечную рекурсию.
OutOfMemoryError
: Переполнение кучи, причём сборщик мусора уже попытался её почистить и беспомощно развёл руками. Обычно это указывает
на утечки памяти, вызванные хранением ссылок на множество ненужных объектов в корневых переменных.
LinkageError
: Базовый класс для различных ошибок при загрузке классов, необходимых для работы выполняемого кода. Сюда относятся в
том числе NoClassDefFoundError и ExceptionInInitializerError.
NoClassDefFoundError
: JVM не может найти класс, к которому пытается обратиться код. Это может случиться, если код был скомпилирован с
зависимостью от какого-то класса или библиотеки, но запущен при отсутствии этого класса/библиотеки в classpath.
ExceptionInInitializerError
: При инициализации статического поля класса или внутри блока static выбросилось исключение, к которому можно
доступиться через метод getCause.
ThreadDeath
: В многопоточной программе чужой поток нагло и бесцеремонно завершил работу нашего потока методом Thread.stop. Если
поток завершается по этому исключению, по умолчанию сообщение об ошибке подавляется и не пишется в консоль.
AssertionError
: Нарушено базовое условие, которое в корректно работающей программе должно выполняться всегда. Исключения этого класса
бросает инструкция assert при запуске JVM с параметром -ea (enable assertions), а также библиотека JUnit при провале
тестов.
Как правило, не стоит выбрасывать исключения типа Error инструкцией throw, кроме исключения AssertionError. Его
принято выбрасывать как «невозможное» исключение, чтобы «заткнуть» выбросом исключения пути выполнения, которые заведомо
никогда не будут выполнены, но компилятор об этом не знает. Часто это приходится делать при использовании перечислимых
типов в инструкции switch:
public enum Stoplight { RED, YELLOW, GREEN } public enum CarState { STOPPED, STOPPING, MOVING } public class Car { public CarState approachIntersection(Intersection intersection) { switch (intersection.getStoplight()) { case RED: stop(); return CarState.STOPPING; case YELLOW: if (stopIfPossible()) { return CarState.STOPPING; } else { return CarState.MOVING; } case GREEN: keepMoving(); return CarState.MOVING; default: // не может случиться throw new AssertionError(); } } public CarState handleStoplightSwitch(Stoplight stoplight) { switch (stoplight) { case RED: return CarState.STOPPED; case YELLOW: prepareToMove(); return CarState.STOPPED; case GREEN: startMoving(); return CarState.MOVING; default: // не может случиться throw new AssertionError(); } } }
В нашем случае у светофора всего три возможных состояния, но компилятор тем не менее требует, чтобы блок switch
обработал невозможную ситуацию default. С помощью throw new AssertionError мы затыкаем компилятор и говорим
сопровождающему код, что эта строка кода заведомо не выполнится.
Ещё один частый use case для AssertionError — блок catch для исключения, невозможного по определению.
Например, стандартные классы URLEncoder и URLDecoder имеют методы, принимающие два параметра: перекодируемую строку
и строку с именем кодировки.
String url = "https://ru.wikipedia.org/wiki/%D0%A1%D1%82%D0%B5%D0%BA"; String decodedUrl = URLDecoder.decode(url, "UTF-8");
Этот код просто так не скомпилируется, потому что метод URLDecoder.decode объявлен как
throws UnsupportedEncodingException. Однако кодировка UTF-8 гарантированно поддерживается в любой реализации JVM,
поэтому на самом деле это исключение никогда не выбросится (но компилятор, увы, об этом не знает). Нам придётся
обернуть этот код в идиому «невозможное исключение» (impossible exception):
try { String url = "https://ru.wikipedia.org/wiki/%D0%A1%D1%82%D0%B5%D0%BA"; String decodedUrl = URLDecoder.decode(url, "UTF-8"); // https://ru.wikipedia.org/wiki/Стек } catch (UnsupportedEncodingException e) { // не может случиться throw new AssertionError(e); }
Большинство методов, работающих с кодировками, имеют версии, принимающие вместо строки с именем кодировки объект
классаCharsetи не бросающиеUnsupportedEncodingException. Им можно передавать константы из класса
StandardCharsets:List<String> fileContents = Files.readAllLines( Paths.get("отчёт.txt"), StandardCharsets.UTF_8); fileContents.forEach(System.out::println);К сожалению, некоторые старые классы, в том числе
URLEncoderиURLDecoder, так и не были обновлены для поддержки
параметров типаCharset.
Исключения времени выполнения (RuntimeException)
Строго говоря, все исключения возникают во время выполнения, но класс RuntimeException занимает особое положение.
Во-первых, RuntimeException и все производные от него исключения являются непроверяемыми. Во-вторых,
многие из этих исключений сигнализируют об ошибках в программном коде и в корректно написанной программе не должны
возникать вообще. Такие исключения полезно выбрасывать в собственных public-методах в качестве предусловий
(preconditions), краткий смысл которых состоит в том, чтобы сказать вызывающему коду: «Ты виноват, такой ситуации вообще
не должно быть».
Вот некоторые самые важные из них:
NullPointerException
: Программа попыталась обратиться к полю или методу ссылки null, либо значение null было передано в метод, не
допускающий null в качестве параметра.
IllegalArgumentException
: Метод был вызван с недопустимым значением параметра. Например, один из конструкторов стандартного класса Color,
принимающий три целых числа RGB, выбрасывает это исключение, если переданные числа не лежат в диапазоне 0–255.
IllegalStateException
: Объект находится в состоянии, в котором выполнение операции невозможно. Например, реализация стека может выбросить
это исключение при попытке извлечь элемент из пустого стека.
IndexOutOfBoundsException
: Попытка обратиться к упорядоченной последовательности элементов (массиву, строке или списку) по индексу, лежащему
вне допустимых значений. Часто происходит при ошибке на единицу, когда в качестве индекса используется length или
size.
NoSuchElementException
: Выбрасывается итератором при попытке прочитать элемент за концом последовательности (когда hasNext() == false). В
корректной реализации итератора это исключение возможно только при ручной работе с итератором и невозможно при
использовании цикла for-each.
UnsupportedOperationException
: Вызываемая операция в принципе запрещена для этого объекта. Например, неизменяемые коллекции выбрасывают это
исключение при попытке изменить их методами set, add или remove.
ArithmeticException
: Вызвана недопустимая арифметическая операция, например, деление на ноль. Операции над числами с плавающей точкой не
выбрасывают это исключение, вместо этого при недопустимой операции они возвращают значение NaN (а при делении
ненулевого числа на ноль — бесконечность).
ClassCastException
: Попытка привести объект к несовместимому типу, например, (String) new Object().
Все эти исключения объединяет то, что в корректно написанной программе они не должны выбрасываться. Если одно из этих
исключений ловится в программе, это знак неверной логики кода. Часто отлов такого исключения можно заменить проверкой;
например, вместо отлова ClassCastException использовать оператор instanceof, вместо IndexOutOfBoundsException
— проверку диапазона (index >= 0 && index < size()), а вместо NoSuchElementException — проверку
Iterator.hasNext().
Прочие исключения (Exception)
Исключения, производные от Exception, но не RuntimeException, являются проверяемыми. Их очень много, и сторонние
библиотеки часто добавляют свои собственные классы исключений. Вот лишь несколько примеров:
ReflectiveOperationException
: Базовый класс для исключений, возникающих при работе с механизмом рефлексии. Сюда относятся IllegalAccessException
(попытка доступиться извне к членам класса с доступом private, protected или package-private), NoSuchMethodException
(метод не найден) и InvocationTargetException (оборачивает исключение, выброшенное вызываемым через рефлексию
методом). Отдельно стоит выделить…
ClassNotFoundException
: Не путать с NoClassDefFoundError. Выбрасывается методом Class.forName, если класс с таким именем не найден. Это
исключение, в отличие от NoClassDefFoundError, предназначено для того, чтобы его перехватывали и обрабатывали.
CloneNotSupportedException
: По умолчанию выбрасывается protected-методом Object.clone, если объект не реализует интерфейс Cloneable. По
каким-то непонятным причинам конченые укурки, проектировавшие Java 1.0, сделали это исключение проверяемым, и при
реализации Cloneable-классов это исключение приходится подавлять.
SQLException
: Базовый класс для ошибок при работе с базами данных через JDBC API.
IOException
: Базовый класс для исключений при операциях ввода-вывода, к которым относятся операции, в том числе, с файловой
системой и сетью. У этого класса очень много подклассов, обозначающих конкретные ситуации; например,
ConnectException бросается при неудачной попытке соединения с сервером.
FileSystemException
: Подкласс IOException, являющийся базовым классом для исключений при операциях с файловой системой.
AccessDeniedException
: Попытка обратиться к файлу, на доступ к которому у пользователя нет прав — например, попытка открыть
защищённый системный файл для записи.
NoSuchFileException
: Попытка обратиться к несуществующему файлу.
Класс
NoSuchFileExceptionпоявился в Java 7 и является частью нового файлового API (классыPathиFiles). В
старых API, спроектированных для Java 6 и ниже, можно встретить более старое исключениеFileNotFoundException,
присутствовавшее ещё в Java 1.0. К сожалению, это исключение не позволяет различить ситуации «файл не найден» и «доступ
запрещён» и выбрасывается старыми API в обоих этих случаях.
Использование проверяемых и непроверяемых исключений
Тема проверяемых и непроверяемых исключений, а также правил их использования, сломала немало копий (и кода). Полного
консенсуса по этому вопросу нет, но можно пользоваться эмпирическим правилом.
Выбрасывайте проверяемые исключения только при одновременном выполнении трёх условий:
- Вызывающий код не может гарантированно избежать ошибочной ситуации, то есть она находится вне его полного контроля.
- Ошибочная ситуация является «стандартной», то есть в любом случае автору вызывающего кода нужно думать о том, что
произойдёт при возникновении ошибки. Например, при попытке открыть файл может оказаться, что файл недоступен. - Вызывающий код может осмысленно обработать ошибку или даже восстановиться после неё.
Хорошими примерами проверяемых исключений являются исключения при работе с файловой системой, сетью, базами данных,
окнами, другими процессами в системе и т.д. Все эти сущности объединяет то, что это внешние ресурсы, корректную работу
которых вызывающий код не может полностью гарантировать. Плохой пример проверяемого исключения — исключение
CloneNotSupportedException, которое может возникнуть только при логической ошибке в использовании метода clone.
Если бы класс CloneNotSupportedException был написан в наши дни, скорее всего, это исключение было бы непроверяемым.
Если хотя бы одно из этих трёх условий не выполняется, используйте непроверяемые исключения. Вот примеры ошибок, для
которых подходят непроверяемые исключения:
- Низкоуровневые ошибки самой JVM и загруженных классов (
Error). - Ошибки в логике программы, необнаружимые на этапе компиляции (
RuntimeException). - Ошибки, при которых продолжение выполнения кода не имеет смысла. Например, в серверных приложениях это могут быть
ошибки конфигурации сервера, при которых приложение вообще не может запуститься, или ошибки доступа к основной базе
данных, с которой работает серверное приложение (здесь само приложение всё равно не сможет восстановиться). Как правило,
такие исключения тоже наследуют отRuntimeException.
Создание исключения
Объекты исключений, как правило, создаются прямо в инструкции throw:
throw new SomeException(параметры);
По соглашению у большинства классов исключений есть четыре конструктора, позволяющие задать исключению сообщение и/или
причину — более низкоуровневое исключение.
SomeException()
SomeException(String message)
SomeException(Throwable cause)
SomeException(String message, Throwable cause)
Это позволяет, с одной стороны, соблюдать инкапсуляцию, не проталкивая низкоуровневые исключения вверх, а с другой
— сохранять информацию о низкоуровневых исключениях для отладочных целей.
try { readConfigFile("server-config.xml"); } catch (XMLStreamException e) { throw new ServerStartupException("Invalid server configuration format", e); } catch (IOException e) { throw new ServerStartupException("Cannot access server configuration", e); }
У некоторых очень старых классов исключений, написанных до выхода Java 1.4, может не быть конструкторов с параметром
cause. Для них можно установить причину после создания объекта с помощью метода initCause:
throw new OldException("Message").initCause(e);
Получение информации об исключении
Все исключения поддерживают три базовых операции:
String getMessage()
: Возвращает короткое, в одно-два предложения, сообщение об ошибке, переданное в объект исключения при его создании.
Throwable getCause()
: Возвращает исключение, послужившее причиной данного исключения, или null, если таковое не было задано. У причины,
в свою очередь, тоже может быть причина; с помощью последовательных вызовов getCause можно восстановить причинную
цепь исключений (causal chain).
void printStackTrace()void printStackTrace(PrintStream s)void printStackTrace(PrintWriter s)
: Выводит трассировку стека (stack trace) в указанный байтовый или символьный поток (по умолчанию — в
System.err). Варианты с PrintStream и PrintWriter бывают полезны, чтобы записать трассировку стека в файл или
сетевой поток, либо получить её в виде строки с помощью StringWriter.
Если у исключения есть причина, методы printStackTrace вслед за трассировкой стека самого исключения печатают
трассировку стека его причины, затем — причины причины и так далее.
По умолчанию для всех исключений, кроме ThreadDeath, при завершении потока по необработанному исключению трассировка
стека записывается в System.err с помощью printStackTrace. Это относится и к главному потоку при аварийном
завершении метода main.
Как пример, вот такая неправильная программа
public class ExceptionChain { private static class BadInitializer { private static final char CONSTANT = "Hello".charAt(5); } public static void main(String[] args) { System.out.println(BadInitializer.CONSTANT); } }
при выполнении выдаст:
Exception in thread "main" java.lang.ExceptionInInitializerError
at ExceptionChain.main(ExceptionChain.java:11)
Caused by: java.lang.StringIndexOutOfBoundsException: String index out of range: 5
at java.lang.String.charAt(String.java:658)
at ExceptionChain$BadInitializer.<clinit>(ExceptionChain.java:7)
... 1 more
Классы Java для обработки исключительных ситуаций из пакета java.lang. Методы класса Throwable. Примеры
Содержание
- 1. Типы исключений, которые поддерживаются системой обработки исключений Java
- 2. Классификация исключений по признаку наличия в операторе throws. Непроверяемые исключения. Проверяемые исключения
- 3. Перечень подклассов непроверяемых исключений из пакета java.lang
- 4. Проверяемые исключения из пакета java.lang
- 5. Какое назначение класса Throwable? Методы класса Throwable
- 6. Пример использования некоторых методов класса Throwable. Разработка собственного класса исключения
- Связанные темы
Поиск на других ресурсах:
1. Типы исключений, которые поддерживаются системой обработки исключений Java
В языке программирования Java разработан эффективный механизм обработки исключений. В основе этого механизма лежат классы образующие иерархию. Для всех классов исключений Java базовым классом есть класс Throwable.
Из класса Throwable унаследованы два основных класса:
- Exception – предназначен для задания исключительных условий, которые перехватываются программой. Если нужно объявить собственный класс (тип) исключений, то этот класс может быть унаследован от класса Exception;
- Error – класс, который предназначен для описания исключений (ошибок) возникающих в самой среде Java. Такие исключения не оговариваются во время нормального выполнения прикладной программы. Примеры системных ошибок: недостаточно памяти, переполнение стека.
Схема верхнего уровня иерархии классов Java приведена на рисунке

Рисунок. Вершина иерархии классов исключений Java
⇑
2. Классификация исключений по признаку наличия в операторе throws. Непроверяемые исключения. Проверяемые исключения
Как известно, метод может генерировать исключения, которые могут быть перехвачены в других методах высших уровней. При этом, метод должен указывать перечень обрабатываемых исключений в операторе throws.
Более подробно о работе оператора throws описывается в теме:
- Операторы throw, throws. Примеры
Если тип сгенерированного исключения есть подклассом стандартного класса RuntimeException, то не обязательно указывать этот тип в перечне оператора throws метода. Такое исключение называется непроверяемым исключением. В этом случае компилятор не проверяет обрабатываются или генерируются такие исключения в некотором месте программы.
Если тип сгенерированного исключения не является подклассом стандартного класса RuntimeException, то это исключение называется проверяемое исключение. В случае генерирования такого типа исключения, его нужно обязательно включать в оператор throws.
⇑
3. Перечень подклассов непроверяемых исключений из пакета java.lang
Среди всего разнообразия классов и интерфейсов пакет java.lang содержит мощный арсенал классов для обработки исключений. Эти классы и интерфейсы составляют основу всех программ на Java. Пакет java.lang автоматически импортируется во все программы.
Ниже приведен перечень подклассов непроверяемых исключений производными от класса RuntimeException и которые определены в пакете java.lang:
- ArithmeticException – арифметическая ошибка (например, деление на ноль);
- ArrayIndexOutOfBoundsException – индекс за пределами массива;
- ArrayStoreException – присваивание элементу массива объекта несовместимого типа;
- ClassCastException – неправильное приведение типов;
- EnumConstantNotPresent – попытка воспользоваться неопределенным значением перечисления;
- IllegalArgumentException – недопустимый аргумент при вызове метода;
- IllegalMonitorStateException – недопустимая контрольная операция;
- IllegalStateException – неверное состояние среды или приложения;
- IllegalThreadStateException – несовместимость запрашиваемой операции с текущим состоянием потока выполнения;
- IndexOutOfBoundsException – выход индекса некоторого типа за допустимые границы;
- NegativeArraySizeException – создание массива отрицательного размера;
- NullPointerException – неправильное использование пустой ссылки;
- NumberFormatException – неправильное преобразование символьной строки в числовой формат;
- SecurityException – попытка нарушения безопасности;
- StringIndexOutOfBounds – попытка доступа по индексу за пределами символьной строки;
- TypeNotPresentException – тип не найден;
- UnsupportedOperationException – найдена неподдерживаемая операция.
⇑
4. Проверяемые исключения из пакета java.lang
Если тип сгенерированного исключения не является подклассом стандартного класса RuntimeException, то это исключение называется проверяемым исключением. В случае генерирования такого типа исключения, его обязательно нужно включать в оператор throws метода.
В языке Java в пакете java.lang реализован ряд проверяемых исключений. Ниже приведен их перечень:
- ClassNotFoundException – класс не найден;
- CloneNotSupportedException – попытка клонировать объект из класса, который не реализует интерфейс Cloneable;
- IllegalAccessException – запрещен доступ к классу;
- InstantiationException – попытка создать объект абстрактного класса или интерфейса;
- InterruptedException – один поток выполнения прерван другим потоком;
- NoSuchFieldException – запрашиваемое поле не существует;
- NoSuchMethodException – запрашиваемый метод не существует;
- ReflectiveOperationException – суперкласс исключений, связанных с рефлексией.
Также, в перечень исключений оператора throws обязательно нужно включать собственноручно разработанные классы исключений для их проверки.
⇑
5. Какое назначение класса Throwable? Методы класса Throwable
Класс Throwable есть базовым для всех стандартных классов исключений Java. Этот класс предоставляет ряд методов, которые можно использовать или переопределять в собственных классах обработки исключений. Эти классы должны быть унаследованы от класса Exception, который унаследован от класса Throwable (см. рисунок). Класс Exception не содержит методов.
Ниже приведен перечень методов класса Throwable.
1. Метод
final void addSuppressed(Throwable исключение)
добавляет заданное исключение в список подавляемых исключений. Этот список связывается с вызывающим (данным) исключением. Метод используется для применения в операторе try с ресурсами.
2. Метод
Throwable fillInStackTrace()
возвращает объект класса Throwable, содержащий полную трассировку стека. Этот объект может быть сгенерирован повторно.
3. Метод
Throwable getCause()
возвращает исключение, лежащее в основе текущего исключения. Метод возвращает null в случае, если такое исключение отсутствует. Этот метод используется при создании цепочек исключений – он вызывает исключение, вызывающее текущее исключение.
4. Метод
String getLocalizedMessage()
возвращает локализованное описание исключения.
5. Метод
String getMessage()
возвращает описание исключения.
6. Метод
StackTraceElement[] getStackTrace()
возвращает массив, содержащий поэлементную трассировку стека в виде объектов класса StackTraceElement.
7. Метод
final Throwable[] getSuppressed()
получает подавленные исключения, связанные с вызывающим исключением, и возвращает массив, который содержит результат. Подавленные исключения генерируются в операторе try с ресурсами.
8. Метод
Throwable initCause(Throwable причина_исключения)
связывает входной параметр причина_исключения с вызывающим исключением, указывая его как причину этого вызывающего исключения. Возвращает ссылку на исключение. Метод используется при создании цепочек исключений.
9. Метод
printStackTrace();
выводит трассировку стека.
10. Метод printStackTrace() имеет еще две перегруженных реализации
void printStackTrace(PrintStream поток_вывода) void printStackTrace(PrintWriter поток_вывода)
Метод направляет трассировку стека в заданный поток_вывода.
11. Метод
void setStackTrace(StackTraceElement элементы[])
устанавливает трассировку стека для заданных элементов.
12. Метод
String toString()
возвращает объект типа String содержащий описание исключения. Этот метод можно вызвать из метода println() при выводе объекта типа Throwable.
⇑
6. Пример использования некоторых методов класса Throwable. Разработка собственного класса исключения
В примере демонстрируется использование некоторых методов класса Throwable:
- getLocalizedMessage();
- getMessage();
- toString();
- getStackTrace();
- fillInStackTrace().
Объявляется класс MyException, унаследованный от класса Exception. В иерархии классов исключений Java класс Exception унаследован от класса Throwable. Поэтому, класс MyException может использовать и переопределять методы класса Throwable.
Текст программы следующий:
import java.util.Scanner; // собственный класс исключения, унаследован от Exception class MyException extends Exception { // переопределенная функция getLocalizedMessage() public String getLocalizedMessage() { return "MyException.getLocalizedMessage()"; } } // класс, содержащий функцию main() public class Train04 { // функция main() тестирует работу класса MyException public static void main(String[] args) { // Ввести число x. Если число за пределами [0..100], // то сгенерировать исключение MyException int x; Scanner sc = new Scanner(System.in); System.out.print("x = "); x = sc.nextInt(); // ввести x try { // сгенерировать исключение (создать объект типа MyException), // если x за пределами [0..100] if ((x<0)||(x>100)) throw new MyException(); System.out.println("OK!"); } catch(MyException e) { // обработка исключения типа MyException, // демонстрация некоторых методов класса Throwable System.out.println("Return from getLocalizedMessage(): " + e.getLocalizedMessage()); System.out.println("Return from getMessage(): " + e.getMessage()); System.out.println("Method printStackTrace(): "); e.printStackTrace(); System.out.println("Method toString(): " + e.toString()); System.out.println("------------------------"); System.out.println("Method getStackTrace(). Stack trace: "); StackTraceElement[] stE; stE = e.getStackTrace(); // метод getStackTrace() for (int i=0;i<stE.length;i++) System.out.println(stE[i].toString()); System.out.println("-------------------------"); System.out.println("Method fillStackTrace(). Stack trace: "); Throwable tA = e.fillInStackTrace(); StackTraceElement[] stE2 = tA.getStackTrace(); for (int i=0; i<stE2.length; i++) System.out.println(stE[i].toString()); System.out.println("-------------------------"); } } }
Объясним некоторые фрагменты кода.
С целью демонстрации в классе MyException переопределяется метод getLocalizedMessage(). При вызове этого метода выводится сообщение из этого переопределенного метода. По данному примеру можно переопределять другие методы класса Throwable.
В функции main() продемонстрировано использование методов класса Throwable. Вводится переменная x, которая проверяется на допустимые значения в пределах то 0 до 100. Если значение x меньше 0 или больше 100, то генерируется исключение типа MyException.
Результат работы программы
x = 200 Return from getLocalizedMessage(): MyException.getLocalizedMessage() Return from getMessage(): null Method printStackTrace(): Method toString(): MyException: MyException.getLocalizedMessage() ------------------------ Method getStackTrace(). Stack trace: Train04.main(Train04.java:36) ------------------------- Method fillStackTrace(). Stack trace: Train04.main(Train04.java:36) ------------------------- MyException: MyException.getLocalizedMessage()
⇑
Связанные темы
- Исключения. Исключительная ситуация. Ключевые слова try, catch, finally. Примеры
- Операторы throw, throws. Примеры
- Класс Exception. Создание собственных классов исключений. Примеры
⇑
Все классы-исключения расширяют класс
Throwabie — непосредственное расширение
класса object.
У класса Throwabie и у всех его расширений
по традиции два конструктора:
-
Throwabie о — конструктор по умолчанию;
-
Throwabie (String message) — создаваемый объект
будет содержать произвольное сообщение
message.
Записанное в конструкторе сообщение
можно получить затем методом getMessage ().
Если объект создавался конструктором
по умолчанию, то данный метод возвратит
null.
Метод tostringo возвращает краткое описание
события, именно он работал в предыдущих
листингах.
Три метода выводят сообщения обо всех
методах, встретившихся по пути «полета»
исключения:
-
printstackTrace() — выводит сообщения в
стандартный вывод, как правило, это
консоль; -
printStackTrace(PrintStream stream) — выводит сообщения
в байтовый поток stream; -
printStackTrace(PrintWriter stream) — выводит сообщения
в символьный поток stream.
У класса Throwabie два непосредственных
наследника — классы Error и Exception. Они не
добавляют новых методов, а служат для
разделения классов-исключений на два
больших семейства — семейство
классов-ошибок (error) и семейство собственно
классов-исключений (exception).
Классы-ошибки, расширяющие класс Error,
свидетельствуют о возникновении сложных
ситуаций в виртуальной машине Java. Их
обработка требует глубокого понимания
всех тонкостей работы JVM. Ее не рекомендуется
выполнять в обычной программе. Не
советуют даже выбрасывать ошибки
оператором throw. He следует делать свои
классы-исключения расширениями класса
Error или какого-то его подкласса.
Имена классов-ошибок, по соглашению,
заканчиваются словом Error.
Классы-исключения, расширяющие класс
Exception, отмечают возникновение обычной
нештатной ситуации, которую можно и
даже нужно обработать. Такие исключения
следует выбросить оператором throw.
Классов-исключений очень много, более
двухсот. Они разбросаны буквально по
всем пакетам J2SDK. В большинстве случаев
вы способны подобрать готовый
класс-исключение для обработки
исключительных ситуаций в своей
программе. При желании можно создать и
свой класс-исключение, расширив класс
Exception или любой его подкласс.
Среди классов-исключений выделяется
класс RuntimeException — прямое расширение
класса Exception. В нем и его подклассах
отмечаются исключения, возникшие при
работе JVM, но не столь серьезные, как
ошибки. Их можно обрабатывать и
выбрасывать, расширять своими классами,
но лучше
доверить это JVM, поскольку чаще всего
это просто ошибка в программе, которую
надо исправить. Особенность исключений
данного класса в том, что их не надо
отмечать в заголовке метода пометкой
throws.
Имена классов-исключений,
по соглашению, заканчиваются словом
Exception.
4. Базовые классы исключений и их методы
5. Проверяемые и непроверяемые исключения
В Java определены проверяемые
(checked) и непроверяемые(unchecked) исключения.
Все типы исключений являются
прямыми наследниками класса Throwable.
К проверяемым исключениям
относятся исключения наследники класса
Exception. Кроме исключений типа RuntimeException.
Проверяемые исключения
должны обрабатываться в ходе работы
программы. Проверка того, что
проверяемые исключения обработаны
в коде, проводиться компилятором и если
проверяемые исключения не обработаны,
код программы не будет компилироваться.
Под обработкой исключения понимается
обрамление кода, в котором может
возникнуть исключение, блоком try {}
catch() {} или передача исключение дальше
с помощью ключевого слова throws. Переданное
далее исключение должно быть обработано
в методах вызывающих данный код.
Исключения типа Error и
RuntimeException относятся к непроверяемым
исключениям. Такие исключения не
обязательны к обработке.
Исключения типа Error – говорят
об исключительных ситуациях возникающих
в ходе работы программы и возникают
из-за внешних условий не зависящих от
самого кода программы.
Исключения типа RuntimeException
– являются внутренними исключениями
и чаще всего не должны обрабатываться
Такие исключения обычно говорят об
имеющихся багах в программе, неправильной
логике работы или неправильном
использовании API. Такие исключения могут
быть обработаны, но обычно имеет больше
смысла устранить имеющиеся баги,
приводящие к возникновению RuntimeExceptions.
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
- #
- #
- #
- #
- #
- #
- #
- #
- #
- #
- #
Короткий ответ
Для того, чтобы конструкция:
catch(Exception e) {
...
}
отлавливала и RuntimeException.
Длинный ответ
@Grundy уже объяснил, что RuntimeException явно прописан в спецификации и то, что данная иерархия была выбрана авторами Java и только они смогут достоверно объяснить, почему был выбран именно такой вариант, а не какой-либо другой.
Я попробую объяснить почему выбранная иерархия имеет смысл.
Error и Exception
Начнем издалека. Есть базовый класс Throwable. Все методы, связанные с выбрасыванием исключений, определены в нем. Его наследники, что Error, что Exception, не объявляют никаких специфичных методов. По сути это один и тот же класс продублированный с разными названиями.
Такая иерархия явно отделяет фатальные системные ошибки (Error) от нефатальных исключений (Exception). В теории, разработчик должен обрабатывать только исключения, а при возникновении ошибок, программа должна прекращать работу. Например, такой блок try:
try {
//какой-то код
} catch(Exception e) {
//обрабатываем исключение
}
Нормально обработает NullPointerException и продолжит работу. Но если возникнет OutOfMemoryError, то исполнение прекратится и ошибка будет выброшена на уровень выше.
Проверяемые исключения
Разработчики Java приняли решение, довольно спорное, что код должен явно обрабатывать все исключения, которые могут возникнуть. Т.е. если код обращается к методу, который может выбросить исключение, то его нужно либо явно обработать с помощью блока try-catch:
try {
//метод, который может выбросить IOException
throwingMethod();
} catch(IOException e) {
//явно обрабатывается
}
либо явно объявить в вызывающем методе с помощью throws:
//Так мы объявляем всему миру, что наш метод опасный
//и может выбросить исключение.
//Любой код, который вызовет метод, должен будет либо
//обработать исключение, либо передать дальше.
void myMethod() throws IOException {
throwingMethod();
}
Если не сделать ни того, ни другого, то код не скомпилируется.
Error — не проверяется, т.к., во-первых, Error не имеет смысла обрабатывать в большинстве случаев, и, во-вторых, ошибки обычно не относятся к какому-то конкретному методу (переполнение памяти может возникнуть в любой момент).
Непроверяемые исключения
Отдельные виды исключений потенциально очень широко распространены. Например, NullPointerException потенциально может возникнуть при вызове почти любого нестатичного метода:
void method(MyClass obj) {
//здесь может быть NPE
obj.method();
//и здесь может быть NPE
obj.getField().method();
//и здесь
showMessage(obj.toString());
}
Явная обработка NullPointerException привела бы к очень неудобному коду, с огромным количеством try catch и throws. Поэтому для таких исключений пришли к компромису и объявили класс RuntimeException.
(Вопрос о том, какие исключения должны наследоваться от RuntimeException — довольно спорный. Есть рекомендации использовать непроверяемые исключения для программных ошибок, но на практике выбор может оказаться сложным)
RuntimeException наследуется от Exception потому-что непроверяемое исключение это все еще исключение, а не ошибка: его можно обработать и оно всегда зависит от кода, а не от сторонних, системных, факторов. И если разработчик решит обрабатывать все исключения:
catch(Exception e) {
//обработка
}
, то должны обрабатываться и возникшие RuntimeException.
Можно ли было сделать по-другому? Да, но есть нюансы. Рассмотрим варианты.
Вариант 1. Разные классы-наследники для проверяемых и непроверяемых исключений.
Можно было бы создать отдельные базовые классы для проверяемых и непроверяемых исключений:
Exception
RuntimeException CheckedException
Но в этом случае возникает вопрос: должен ли быть проверяемым Exception и его наследники? Если да, то класс CheckedException теряет смысл и получаем существующую иерархию. Если нет, то теряет смысл RuntimeException. Тогда получаем второй вариант
Вариант 2. Проверяемые исключения наследуются от непроверяемых
Exception (unchecked)
CheckedException (checked)
Такая иерархия вполне допустима, но разработчики Java решили, что базовый класс должен быть проверяемым. Это соответствует выбранной философии: исключения должны быть проверяемыми по-умолчанию и непроверяемыми только если их повсеместная проверка вызывает затруднения. С этой философией не все согласны, но имеем, что имеем.
Итог
Почему RuntimeException (unchecked), наследуется от класса Exception, который является (checked)?
По следующим причинам:
-
Проверяемость тех или иных классов явно прописана в спецификации и не связана с какими-либо свойствами классов-исключений. Наследование имеет чисто организационный/иллюстративный характер и не связано с наследованием свойств/методов.
-
Проверяемое исключение — это исключение, а не ошибка, и должно обрабатываться как исключение.
-
Разработчики Java приняли решение, что базовый класс исключений должен быть проверяемым.
Афоризм
Ох и помотало же тебя по чужим кроватям!
Лариса Гузеева
Поддержка проекта
Если Вам сайт понравился и помог, то будем признательны за Ваш «посильный» вклад в его поддержку и развитие
• Yandex.Деньги
410013796724260
• Webmoney
R335386147728
Z369087728698
| 1. Понятие «Исключение» |
| 2. Операторы исключений |
| 3. Оператор throws |
| 4. Блоки кода try/catch и try/finally |
| 5. Может ли блок finally не выполняться? |
| 6. Проверяемые и непроверяемые исключения |
| 7. Возбуждение исключения |
| 8. Определение исключения в сигнатуре метода |
| 9. Особенность RuntimeException |
| 10. Возбуждение исключения в методе main |
| 11. Множественные исключения |
| 12. Последовательность нескольких блоков catch |
| 13. Поглащение исключений в блоке try…finally |
| 14. Исключение SQLException |
| 15. Ошибка Error |
| 16. Обобщение исключений |
| 17. Логирование исключений |
Вопросы и ответы для собеседование по Java, Содержание.
Вопросы и ответы для собеседование по Java, часть 1.
Вопросы и ответы для собеседование по Java, часть 2.
Вопросы и ответы для собеседование по Java, часть 4.
Вопросы и ответы для собеседование по Java, часть 5.
Вопросы и ответы для собеседование по Java, часть 6.
1. Понятие «Исключение»
Исключение — это ошибка, возникающая во время выполнения программы. Причины возникновения исключения
могут разные, например :
- некорректно определены (не определены) данные;
- невозможно прочитать или создать файл;
- обрыв сетевого соединения или соединения с сервером базы данных.
Исключение в Java является объектом. Поэтому они могут не только создаваться автоматически виртуальной
машиной JVM при возникновении исключительной ситуации, но и порождаться самим разработчиком.
2. Операторы исключений
Java имеет пять ключевых операторов для определения блока исключений, перехвата и возбуждения исключений :
- try — начала блока кода, в котором может возникнуть исключение, и которое следует перехватить;
- catch — начала блока кода, предназначенного для перехвата и обработки исключений (параметром catch
является тип ожидаемого исключения); - throw — оператор для генерации исключений;
- throws — ключевое слово, используемое в сигнатуре метода, и обозначающее, что метод
потенциально может вызвать исключение с определенным типом; - finally — начала дополнительного блока кода, размещаемый после последнего блока catch. Блок finally
не является обязательным, но всегда получает управление.
Общая структура «перехвата» исключительной ситуации выглядит следующим образом :
try {
// код программы, который может привести к ошибке
} catch(Exception e ) {
// код программы для обработки исключений
} finally {
// выполнение блока программы независимо от наличия исключения
}
3. Оператор throws
Оператор throws включается в сигнатуру метода с целью обозначения возожности возникновения
исключительной ситуации с определенным типом. Использовать данный оператор следует в описании тех методов,
которые могут возбуждать исключения, но сами их не обрабатывают. Таким образом, оператором throws метод
предупреждает другие методы, вызывающие данный, что у него могут быть вызваны необработанные исключения,
чтобы вызывающие методы могли защитить себя от этих исключений.
public class TestThrow
{
static void method() throws IllegalAccessException
{
System.out.println("inside method");
// . . .
throw new IllegalAccessException
("Exception in method");
}
public static void main(String args[])
{
try {
method();
} catch(IllegalAccessException e) {
System.out.println("Catch inside main : " +
e.getMessage());
}
}
}
4. Блоки кода try/catch и try/finally
Каждый оператор try требует наличия либо catch, либо finally, либо сочетания catch и finally. Блок кода finally
не является обязательным, и может отсутствовать при использовании try/catch. Оператором finally создаётся блок кода,
который должен быть выполнен после завершения блока try/catch.
Если необходимо гарантировано выполнить определенный участок кода, то используется finally. Связка try/finally
позволяет обеспечить выполнение блока кода независимо от того, какие исключения были возбуждены и перехвачены,
даже в тех случаях, когда в методе нет соответствующего возбужденному исключению раздела catch.
Пример использования try/finally представлен здесь.
5. Может ли блок finally не выполняться?
Код блока finally не будет исполнен, если в код программы включен предшествующий блоку finally системный выход.
Следующий пример демонстрирует данную ситуацию.
try {
System.exit(0);
} catch(Exception e) {
System.err.println(e.getMessage());
} finally {
// код блока
}
6. Проверяемые и непроверяемые исключения
Все исключения делятся на «проверяемые» (checked) и «непроверяемые» (unchecked). Данное свойство присуще
базовому классу исключения Throwable и передается по наследству (Error, Exception, RuntimeException). В исходном
коде класса исключения данное свойство недоступно. Ниже представлена иерархия классов исключений.
Object
|
Throwable(CHECKED)
/
Error(UNCHECKED) Exception(CHECKED)
|
RuntimeException(UNCHECKED)
Исключения Throwable и Exception, а также все их наследники, за исключением Error и RuntimeException,
являются «проверяемыми» checked исключениями. Error и RuntimeException, а также все их наследники, относятся
к «непроверяемым» unchecked исключениям.
Проверка исключения на checked выполняется компилятором (compile-time checking). Непроверяемые исключения
можно перехватить (catch) в момент исполнения программы (runtime checking).
Java – это язык программирования со статической типизацией, т.е. его компилятор отслеживает корректности
использования типов : наличие полей и методов, checked исключения, и т.д. Следующий пример демонстрирует наличие
двух ошибок программирования, определенные на этапе копиляции.
public class TestException
{
public static Double divide(int i1, int i2) throws Exception {
if (i2 != 0)
return new Double (i2 / i2);
else {
Throwable e = new Exception();
throw e; // Unhandled exception type Throwable
}
}
public static void main(String[] args) {
Object obj = "Hello!";
char c = obj.charAt(0); // The method charAt(int) is
// undefined for the type Object
}
}
Сигнатура метода divide (операция деления) включает определение возможного исключения типа Exception, наследуемого
от Throwable. Если делитель (i2) равен 0, то создается объект исключения типа Throwable и возбуждается исключение
(throw t), которое не пропускает компилятор, т.к. тип возбуждаемого исключения не соответствует типу исключения в
сигнатуре метода. Если в сигнатуре метода определить исключение типа Throwable, то ошибки не будет.
В методе main определен объект obj с инициализацией определенным значением. В следующей строке компилятор находит
ошибку, связанную с отсутствием метода charAt(int) в объекте типа Object. Если выполнить приведение типа obj к String,
то компилятор пропустит код : char c = ((String)ref).charAt(0).
Пример unchecked исключения представлен здесь.
7. Возбуждение исключения
Как было отмечено выше, исключение является объектом, который можно создать программно. Чтобы возбудить (выбросить)
исключение используется оператор throw.
Exception e = new SQLException(); throw e;
8. Определение исключения в сигнатуре метода
В сигнатуре метода можно определить возможное проверяемое (checked) исключение. Следующий
пример демонстрирует определение исключения в сигнатуре метода f1() и его перехват в конструкторе класса.
import java.io.EOFException;
import java.io.FileNotFoundException;
public class TestException
{
public TestException()
{
try {
f1();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public void f1() throws FileNotFoundException {
throw new FileNotFoundException();
}
public static void main(String[] args)
{
new TestException ();
}
}
9. Особенность RuntimeException
Исключение RuntimeException расширяет свойства Exception и является базовым классом для ошибок во время выполнения
приложения. Данное исключение относится к необрабатываемым исключениям (unchecked). Согласно описанию класса это
исключение может возникнуть во время нормальной работы JVM.
Следующий код демонстрирует пример использования непроверяемого исключения NumberFormatException (наследующего
свойства RuntimeException). В функции parseInt при преобразовании строкового значения в число в режиме run-time может
возникнуть исключение. Можно метод функции Integer.parseInt() «обернуть» в try/catch, а можно передать обработку
исключения функции в вызывающий метод, для чего в сигнатуре определяется соответствующее исключение (throws).
public int parseInt(String s) throws NumberFormatException
{
return Integer.parseInt(s);
}
10. Возбуждение исключения в методе main
Если в методе main возбудить исключение, то оно будет передано в виртуальную машину Java (JVM).
11. Множественные исключения
В сигнатуре метода можно определить несколько возможных исключений. Для этого используется оператор throws
и исключения, разделенные запятыми. Следующий пример демонстрирует метод callMethods с множественными
возможными исключениями :
import java.io.EOFException;
import java.io.FileNotFoundException;
public class TestException
{
public void callMethods()
throws EOFException, FileNotFoundException
{
if (f1())
f0();
}
public void f0() throws EOFException {
// ...
throw new EOFException();
}
public boolean f1() throws FileNotFoundException {
// ...
throw new FileNotFoundException();
}
}
Чтобы перехватить несколько возможных исключений можно искользовать конструкцию try с несколькими catch.
try {
if (f1())
f0();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (EOFException e) {
e.printStackTrace();
}
12. Последовательность нескольких блоков catch
При определение нескольких блоков catch следует руководствоваться правилом обработки исключений от «младшего»
к старшему. Т.е. нельзя размещать первым блоком catch (Exception e) {…}, поскольку все остальные блоки catch()
уже не смогут перехватить исключение. Помните, что Exception является базовым классом, поэтому его стоит размещать
последним.
Рассмотрим следующую иерархию наследования исключений :
java.lang.Object
java.lang.Throwable
java.lang.Exception
java.io.IOException
java.io.EOFException
Cамым младшим исключением является EOFException, поэтому он должен располагаться перед IOException и Exception,
если используется несколько блоков catch с данными типами исключений. Следующий код является демонстрацией
данного принципа.
String x = "Hello";
try {
if (!x.equals("Hello"))
throw new IOException();
else
throw new EOFException();
} catch (EOFException e) {
System.err.println("EOFException : " + e.getMessage());
} catch (IOException e) {
System.err.println("IOException : " + e.getMessage());
} catch (Exception e) {
System.err.println("Exception : " + e.getMessage());
}
13. Поглащение исключений в блоке try…finally
Если было вызвано два исключения — одно в блоке try, а второе в finally — то, при отсутствии catch,
исключение в finally «проглотит» предыдущее исключение. Следует блоки с возможными исключениями всегда
обрамлять операторами try/catch, чтобы не потерять важную информацию. Следующий пример демонстрирует
«поглащение» исключения в блоке try новым исключением в блоке finally.
public class TestException
{
public TestException() {
try {
System.out.println(absorbingEx());
} catch (EOFException e) {
System.out.println(e.getMessage());
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
public String absorbingEx() throws IOException,
EOFException
{
try {
throw new EOFException("EOFException");
// } catch (EOFException e) {
// System.out.println("catch " + e.getMessage());
} finally {
throw new IOException("finally IOException");
}
}
public static void main(String[] args) {
new TestException();
System.exit(0);
}
}
В результате в консоль будет выведено следующее сообщение :
Чтобы не «потерять» исключение, необходимо его корректно перехватить и обработать. В примере следует
убрать комментарий с блока catch.
14. Исключение SQLException
Исключение SQLException связано с ошибками при работе с базой данных. Данное исключением относится
к checked исключениям, и, следовательно, проверяется на этапе компиляции.
java.lang.Object
java.lang.Throwable
java.lang.Exception
java.sql.SQLException
Споры вокруг SQLException связаны с тем, что исключение возникает во время исполнения, а обрабатывать
его приходится в коде, чтобы не ругался компилятор; может быть следовало бы отнести его к unchecked
run-time исключениям? Убедительный довод разработчиков данного исключения связан с тем, что необходимо
программисту обработать свои возможные ошибки при работе с базой данных.
15. Ошибка Error
Ошибка Error относится к подклассу не проверяемых (unchecked) исключений, которая показывает серьезные
проблемы, возникающие во время выполнения программы. Большинство из ошибок данного класса сигнализируют о
ненормальном ходе выполнения программы, т.е. о возникновении критических проблем.
Согласно спецификации Java, не следует пытаться обрабатывать Error в собственной программе, поскольку
они связаны с проблемами уровня JVM. Исключения такого рода возникают, если, например,
закончилась память, доступная виртуальной машине.
16. Обобщение исключений
При определении в сигнатуре метода возможных исключений можно вместо нескольких проверяемых исключений
указать общее (базовое) java.lang.Throwable. В этом случае, компилятор «пропустит код» и программа возможно
отработает без сбоев. Например :
public void callCommonException() throws Exception {
Object obj = new Object();
method(obj);
}
public void method(Object obj)
throws NumberFormatException,
IllegalArgumentException {
// ...
}
Использование Exception или Throwable в сигнатуре метода делает почти невозможным правильное обращение с
исключениями при вызове метода. Вызывающий метод получает только информацию о том, что что-то может отработать
некорректно.
Перехват обобщенных исключений не позволяет «решить» проблему, т.е. «вылечить» программу, а помогает только
обойти периодически возникающую проблему. Это может привести к нескольким непредвиденным ошибкам в других местах
приложения.
17. Логирование исключений
Лучше всего логировать (регистрировать) исключение в месте его обработки. Это связано с тем, что именно
в данном месте кода достаточно информации для описания возникшей проблемы. Кроме этого, одно и то же исключение
при вызове одного и того же метода можно перехватывать в разных местах программы; регистрировать же следует в
одном месте.
Иногда исключение может быть частью ожидаемого поведения. В этом случае нет необходимости его регистрировать.
Вопросы и ответы для собеседование по Java, Содержание.
Вопросы и ответы для собеседование по Java, часть 1.
Вопросы и ответы для собеседование по Java, часть 2.
Вопросы и ответы для собеседование по Java, часть 4.
Вопросы и ответы для собеседование по Java, часть 5.
Вопросы и ответы для собеседование по Java, часть 6.
В продолжение первой части серии рассмотрим тему про Exception.
Exception:
-
Что такое исключение (Exception)
-
Какая иерархия исключений в Java
-
Какая разница между Error, Exception и RuntimeException
-
Как обработать исключения в Java
Рекомендуем публикацию по теме
Что такое исключение (Exception)
Исключением является событие ошибки, которое может произойти во время выполнения программы и нарушить ее нормальный поток выполнения. Исключение может быть вызвано различными ситуациями, такими как: неправильные данные, введенные пользователем, сбой оборудования, нехватка ресурсов, сбой сетевого подключения и т. д.
В Java исключения являются объектами и наследуются от класса Object.
Какая иерархия исключений в Java
Все исключения в Java наследуются от класса Throwable. Класс Throwable имеет два наследника — Error и Exception. Также есть RuntimeException, который наследуется от Exception. Когда идет речь об ошибках в Java, обычно имеют ввиду эти три класса: Error, Exception и RuntimeException. Все другие ошибки наследуются от этих классов.
Все исключения делятся на два типа: проверяемые исключения (checked) и непроверяемые исключения (unchecked).
Проверяемые исключения (checked) представляют собой ошибки, которые нужно обрабатывать в программе разработчику вручную. К этому типу относятся все потомки класса Exception (но не RuntimeException), а также класс Throwable.
Проверяемые исключения проверяются во время компиляции. Это означает, что на этапе компиляции компилятор проверяет, все ли проверяемые исключения были обработаны, если нет, то выдается ошибка компиляции.
Непроверяемые исключения (unchecked) представляют собой ошибки, которые не нужно обрабатывать вручную. К ним относятся классы Error и RuntimeException (наследник класса Exception) и их наследники. Это означает, что если программа генерирует непроверяемое исключение, и даже если вы не обрабатывали или не объявляли это исключение, программа не выдаст ошибку компиляции.
Рекомендуем курс по теме
Какая разница между Error, Exception и RuntimeException
Error представляет исключения, которые, согласно спецификации Java, не следует пытаться обрабатывать в собственной программе, поскольку они связаны с проблемами JVM.
Например, исключения такого рода возникают, если закончилась память, доступная виртуальной машине, и ловить такую ошибку не имеет смысла, так как JVM не сможет обеспечить дополнительную память. Наследуется от Throwable.
Далее перечислим несколько часто встречающихся наследников класса Error:
OutOfMemoryError — исключение возникает, когда не хватает памяти для создания новых объектов.
StackOverflowError — исключение возникает, когда происходит переполнение стека из-за глубокой рекурсии или отсутствии выхода из рекурсии.
NoClassDefFoundError — исключение возникает, когда приложение пытается загрузить класс. Например, создание нового объекта с использованием выражения «new».
Exception наследуется от Throwable. Exception и все его подклассы являются проверяемыми исключениями (checked), кроме RuntimeException.
Далее перечислим несколько часто встречающихся проверяемых (checked) исключений, которые наследуются от Exception:
IOException — базовый класс исключений для ошибок, связанных с операциями ввода-вывода.
Наследники: FileNotFoundException, UnsupportedEncodingException, EOFException, SocketException и т.д.
SQLException — базовый класс исключений, возникающих при работе с БД.
Наследники: SQLSyntaxErrorException, SQLFeatureNotSupportedException, SQLTimeoutException и т.д.
ClassNotFoundException — исключение возникает, когда приложение загружает класс через строковое имя (Class.forName, ClassLoader.findSystemClass, ClassLoader.loadClass)
RuntimeException наследуется от Exception. RuntimeException и все его подклассы являются непроверяемыми исключениями (unchecked).
Далее перечислим несколько часто встречающихся непроверяемых (unchecked) исключений, которые наследуются от RuntimeException:
NullPointerException — исключение, которое возникает при попытке использовать ссылку, которая не указывает ни на одно место в памяти (null). Вызов метода по ссылке null или попытка получить доступ к полю ссылки null вызовут NullPointerException. Один из самых часто встречающихся типов ошибок. Означает чаще всего ошибку разработчика.
ArithmeticException — исключение, которое возникает при ошибочных арифметических операциях. Например, деление на ноль или переполнение int, long и т.д.
ArrayIndexOutOfBoundsException — исключение, которое возникает при попытке доступа по недопустимому индексу в массиве. Индекс либо отрицательный, либо больше или равен размеру массива.
StringIndexOutOfBoundsException — исключение, которое возникает при попытке доступа по недопустимому индексу в строке. Индекс либо отрицательный, либо больше или равен размеру массива.
ClassCastException — исключение, которое возникает при попытке приведения одного типа объекта к подклассу другого типа объекта, экземпляром которого он не является.
Как обработать исключения в Java
В Java есть пять ключевых слов для работы с исключениями: try, catch, finally, throw, throws.
Для обработки исключений используют конструкцию вида try…catch…finally и c Java 1.7 можно использовать конструкцию try-with-resources.
Первый способ:
try {
//код, який може привести до помилки
}
catch (Exception e ){
//код, який обробляє виключення
} finally {
//запускається в будь-якому випадку (блок finally не обов'язковий)
}
Первый способ не подходит для работы с ресурсами.
Второй способ:
try (OutputStream stream = openOutputStream()) {
// щось робимо зі stream
}
try-with-resource можно использовать только над классами, которые наследуются от интерфейса Autoclosable. Это синтаксический сахар, компилятор во время компиляции превращает try-with-resource в обычный try-catch-finally и в блоке finally вызывает метод close у объекта, который указан в скобках после слова try.
В следующей части поговорим о Java Collections. Спасибо большое всем, кто дочитал )
Исключения

try
Оператор throw
Оператор throws
Оператор finally
Встроенные исключения Java
Создание собственных классов исключений
Исключение — это нештатная ситуация, ошибка во время выполнения программы. Самый простой пример — деление на ноль. Можно вручную отслеживать возникновение подобных ошибок, а можно воспользоваться специальным механизмом исключений, который упрощает создание больших надёжных программ, уменьшает объём необходимого кода и повышает уверенность в том, что в приложении не будет необработанной ошибки.
В методе, в котором происходит ошибка, создаётся и передаётся специальный объект. Метод может либо обработать исключение самостоятельно, либо пропустить его. В любом случае исключение ловится и обрабатывается. Исключение может появиться благодаря самой системе, либо вы сами можете создать его вручную. Системные исключения возникают при неправильном использовании языка Java или запрещённых приёмов доступа к системе. Ваши собственные исключения обрабатывают специфические ошибки вашей программы.
Вернёмся к примеру с делением. Деление на нуль может предотвратить проверкой соответствующего условия. Но что делать, если знаменатель оказался нулём? Возможно, в контексте вашей задачи известно, как следует поступить в такой ситуации. Но, если нулевой знаменатель возник неожиданно, деление в принципе невозможно, и тогда необходимо возбудить исключение, а не продолжать исполнение программы.
Существует пять ключевых слов, используемых в исключениях: try, catch, throw, throws, finally. Порядок обработки исключений следующий.
Операторы программы, которые вы хотите отслеживать, помещаются в блок try. Если исключение произошло, то оно создаётся и передаётся дальше. Ваш код может перехватить исключение при помощи блока catch и обработать его. Системные исключения автоматически передаются самой системой. Чтобы передать исключение вручную, используется throw. Любое исключение, созданное и передаваемое внутри метода, должно быть указано в его интерфейсе ключевым словом throws. Любой код, который следует выполнить обязательно после завершения блока try, помещается в блок finally
Схематически код выглядит так:
try {
// блок кода, где отслеживаются ошибки
}
catch (тип_исключения_1 exceptionObject) {
// обрабатываем ошибку
}
catch (тип_исключения_2 exceptionObject) {
// обрабатываем ошибку
}
finally {
// код, который нужно выполнить после завершения блока try
}
Существует специальный класс для исключений Trowable. В него входят два класса Exception и Error.
Класс Exception используется для обработки исключений вашей программой. Вы можете наследоваться от него для создания собственных типов исключений. Для распространённых ошибок уже существует класс RuntimeException, который может обрабатывать деление на ноль или определять ошибочную индексацию массива.
Класс Error служит для обработки ошибок в самом языке Java и на практике вам не придётся иметь с ним дело.
Прежде чем научиться обрабатывать исключения, нам (как и нормальному любопытному коту) хочется посмотреть, а что происходит, если ошибку не обработать. Давайте разделим число котов в вашей квартире на ноль, хотя мы и знаем, что котов на ноль делить нельзя!
int catNumber;
int zero;
catNumber = 1; // у меня один кот
zero = 0; // ноль, он и в Африке ноль
int result = catNumber / zero;
Я поместил код в обработчик щелчка кнопки. Когда система времени выполнения Java обнаруживает попытку деления на ноль, она создаёт объект исключения и передаёт его. Да вот незадача, никто не перехватывает его, хотя это должны были сделать вы. Видя вашу бездеятельность, объект перехватывает стандартный системный обработчик Java, который отличается вредных характером. Он останавливает вашу программу и выводит сообщение об ошибке, которое можно увидеть в журнале LogCat:
Caused by: java.lang.ArithmeticException: divide by zero at ru.alexanderklimov.test.MainActivity.onClick(MainActivity.java:79)
Как видно, созданный объект исключения принадлежит к классу ArithmeticException, далее системный обработчик любезно вывел краткое описание ошибки и место возникновения.
Вряд ли пользователи вашей программы будут довольны, если вы так и оставите обработку ошибки системе. Если программа будет завершаться с такой ошибкой, то скорее всего вашу программу просто удалят. Посмотрим, как мы можем исправить ситуацию.
Поместим проблемный код в блок try, а в блоке catch обработаем исключение.
int catNumber;
int zero;
try { // мониторим код
catNumber = 1; // у меня один кот
zero = 0; // ноль, он и в Африке ноль
int result = catNumber / zero;
Toast.makeText(this, "Не увидите это сообщение!", Toast.LENGTH_LONG).show();
} catch (ArithmeticException e) {
Toast.makeText(this, "Нельзя котов делить на ноль!", Toast.LENGTH_LONG).show();
}
Toast.makeText(this, "Жизнь продолжается", Toast.LENGTH_LONG).show();
Теперь программа аварийно не закрывается, так как мы обрабатываем ситуацию с делением на ноль.
В данном случае мы уже знали, к какому классу принадлежит получаемая ошибка, поэтому в блоке catch сразу указали конкретный тип. Обратите внимание, что последний оператор в блоке try не срабатывает, так как ошибка происходит раньше строчкой выше. Далее выполнение передаётся в блок catch, далее выполняются следующие операторы в обычном порядке.
Операторы try и catch работают совместно в паре. Хотя возможны ситуации, когда catch может обрабатывать несколько вложенных операторов try.
Если вы хотите увидеть описание ошибки, то параметр e и поможет увидеть ёго.
catch (ArithmeticException e) {
Toast.makeText(this, e + ": Нельзя котов делить на ноль!", Toast.LENGTH_LONG).show();
}
По умолчанию, класс Trowable, к которому относится ArithmeticException возвращает строку, содержащую описание исключения. Но вы можете и явно указать метод e.toString.
Несколько исключений
Фрагмент кода может содержать несколько проблемных мест. Например, кроме деления на ноль, возможна ошибка индексации массива. В таком случае вам нужно создать два или более операторов catch для каждого типа исключения. Причём они проверяются по порядку. Если исключение будет обнаружено у первого блока обработки, то он будет выполнен, а остальные проверки пропускаются и выполнение программы продолжается с места, который следует за блоком try/catch.
int catNumber;
int zero;
try { // мониторим код
catNumber = 1; // у меня один кот
zero = 1; // ноль, он и в Африке ноль
int result = catNumber / zero;
// Создадим массив из трёх котов
String[] catNames = {"Васька", "Барсик", "Мурзик"};
catNames[3] = "Рыжик";
Toast.makeText(this, "Не увидите это сообщение!", Toast.LENGTH_LONG).show();
} catch (ArithmeticException e) {
Toast.makeText(this, e.toString() + ": Нельзя котов делить на ноль!", Toast.LENGTH_LONG).show();
}
catch (ArrayIndexOutOfBoundsException e) {
Toast.makeText(this, "Ошибка: " + e.toString(), Toast.LENGTH_LONG).show();
}
Toast.makeText(this, "Жизнь продолжается", Toast.LENGTH_LONG).show();
В примере мы добавили массив с тремя элементами, но обращаемся к четвёртому элементу, так как забыли, что отсчёт у массива начинается с нуля. Если оставить значение переменной zero равным нулю, то сработает обработка первого исключения деления на ноль, и мы даже не узнаем о существовании второй ошибки. Но допустим, что в результате каких-то вычислений значение переменной стало равно единице. Тогда наше исключение ArithmeticException не сработает. Но сработает новое добавленное исключение ArrayIndexOutOfBoundsException. А дальше всё пойдёт как раньше.
Тут всегда нужно помнить одну особенность. При использовании множественных операторов catch обработчики подклассов исключений должные находиться выше, чем обработчики их суперклассов. Иначе, суперкласс будет перехватывать все исключения, имея большую область перехвата. Иными словами, Exception не должен находиться выше ArithmeticException и ArrayIndexOutOfBoundsException. К счастью, среда разработки сама замечает непорядок и предупреждает вас, что такой порядок не годится. Увидев такую ошибку, попробуйте перенести блок обработки исключений ниже.
Вложенные операторы try
Операторы try могут быть вложенными. Если вложенный оператор try не имеет своего обработчика catch для определения исключения, то идёт поиск обработчика catch у внешнего блока try и т.д. Если подходящий catch не будет найден, то исключение обработает сама система (что никуда не годится).
Оператор throw
Часть исключений может обрабатывать сама система. Но можно создать собственные исключения при помощи оператора throw. Код выглядит так:
throw экземпляр_Throwable
Вам нужно создать экземпляр класса Throwable или его наследников. Получить объект класса Throwable можно в операторе catch или стандартным способом через оператор new.
Мы могли бы написать такой код для кнопки:
Cat cat;
public void onClick(View view) {
if(cat == null){
throw new NullPointerException("Котик не инициализирован");
}
}
Мы объявили объект класса Cat, но забыли его проинициализировать, например, в onCreate(). Теперь нажатие кнопки вызовет исключение, которое обработает система, а в логах мы можем прочитать сообщение об ошибке. Возможно, вы захотите использовать другое исключение, например, throw new UnsupportedOperationException(«Котик не инициализирован»);.
В любом случае мы передали обработку ошибки системе. В реальном приложении вам нужно обработать ошибку самостоятельно.
Поток выполнения останавливается непосредственно после оператора throw и другие операторы не выполняются. При этом ищется ближайший блок try/catch соответствующего исключению типа.
Перепишем пример с обработкой ошибки.
public void onClick(View view) {
if (cat == null) {
try {
throw new NullPointerException("Кота не существует");
} catch (NullPointerException e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
}
}
}
Мы создали новый объект класса NullPointerException. Многие классы исключений кроме стандартного конструктора по умолчанию с пустыми скобками имеют второй конструктор с строковым параметром, в котором можно разместить подходящую информацию об исключении. Получить текст из него можно через метод getMessage(), что мы и сделали в блоке catch.
Теперь программа не закроется аварийно, а будет просто выводить сообщения в всплывающих Toast.
Оператор throws
Если метод может породить исключение, которое он сам не обрабатывает, он должен задать это поведение так, чтобы вызывающий его код мог позаботиться об этом исключении. Для этого к объявлению метода добавляется конструкция throws, которая перечисляет типы исключений (кроме исключений Error и RuntimeException и их подклассов).
Общая форма объявления метода с оператором throws:
тип имя_метода(список_параметров) throws список_исключений {
// код внутри метода
}
В фрагменте список_исключений можно указать список исключений через запятую.
Создадим метод, который может породить исключение, но не обрабатывает его. А в щелчке кнопки вызовем его.
// Метод без обработки исключения
public void createCat(){
Toast.makeText(this, "Вы создали котёнка", Toast.LENGTH_LONG).show();
throw new NullPointerException("Кота не существует");
}
// Щелчок кнопки
public void onClick(View v) {
createCat();
}
Если вы запустите пример, то получите ошибку. Исправим код.
// Без изменений
public void createCat() throws NullPointerException {
Toast.makeText(this, "Вы создали котёнка", Toast.LENGTH_LONG).show();
throw new NullPointerException("Кота не существует");
}
// Щелчок кнопки
public void onClick(View v) {
try {
createCat();
} catch (NullPointerException e) {
// TODO: handle exception
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
}
}
Мы поместили вызов метода в блок try и вызвали блок catch с нужным типом исключения. Теперь ошибки не будет.
Оператор finally
Когда исключение передано, выполнение метода направляется по нелинейному пути. Это может стать источником проблем. Например, при входе метод открывает файл и закрывает при выходе. Чтобы закрытие файла не было пропущено из-за обработки исключения, был предложен механизм finally.
Ключевое слово finally создаёт блок кода, который будет выполнен после завершения блока try/catch, но перед кодом, следующим за ним. Блок будет выполнен, независимо от того, передано исключение или нет. Оператор finally не обязателен, однако каждый оператор try требует наличия либо catch, либо finally.
Существуют несколько готовых системных исключений. Большинство из них являются подклассами типа RuntimeException и их не нужно включать в список throws. Вот небольшой список непроверяемых исключений.
- ArithmeticException — арифметическая ошибка, например, деление на нуль
- ArrayIndexOutOfBoundsException — выход индекса за границу массива
- ArrayStoreException — присваивание элементу массива объекта несовместимого типа
- ClassCastException — неверное приведение
- EnumConstantNotPresentException — попытка использования неопределённого значения перечисления
- IllegalArgumentException — неверный аргумент при вызове метода
- IllegalMonitorStateException — неверная операция мониторинга
- IllegalStateException — некорректное состояние приложения
- IllegalThreadStateException — запрашиваемая операция несовместима с текущим потоком
- IndexOutofBoundsException — тип индекса вышел за допустимые пределы
- NegativeArraySizeException — создан массив отрицательного размера
- NullPointerException — неверное использование пустой ссылки
- NumberFormatException — неверное преобразование строки в числовой формат
- SecurityException — попытка нарушения безопасности
- StringIndexOutOfBounds — попытка использования индекса за пределами строки
- TypeNotPresentException — тип не найден
- UnsupportedOperationException — обнаружена неподдерживаемая операция
Список проверяемых системных исключений, которые можно включать в список throws.
- ClassNotFoundException — класс не найден
- CloneNotSupportedException — попытка клонировать объект, который не реализует интерфейс Cloneable
- IllegalAccessException — запрещен доступ к классу
- InstantiationException — попытка создать объект абстрактного класса или интерфейса
- InterruptedException — поток прерван другим потоком
- NoSuchFieldException — запрашиваемое поле не существует
- NoSuchMethodException — запрашиваемый метод не существует
- ReflectiveOperationException — исключение, связанное с рефлексией
Создание собственных классов исключений
Система не может предусмотреть все исключения, иногда вам придётся создать собственный тип исключения для вашего приложения. Вам нужно наследоваться от Exception (напомню, что этот класс наследуется от Trowable) и переопределить нужные методы класса Throwable. Либо вы можете наследоваться от уже существующего типа, который наиболее близок по логике с вашим исключением.
- final void addSuppressed(Throwable exception) — добавляет исключение в список подавляемых исключений (JDK 7)
- Throwable fillInStackTrace() — возвращает объект класса Throwable, содержащий полную трассировку стека.
- Throwable getCause() — возвращает исключение, лежащее под текущим исключение или null
- String getLocalizedMessage() — возвращает локализованное описание исключения
- String getMessage() — возвращает описание исключения
- StackTraceElement[] getStackTrace() — возвращает массив, содержащий трассировку стека и состояний из элементов класса StackTraceElement
- final Throwable[] getSuppressed() — получает подавленные исключения (JDK 7)
- Throwable initCause(Throwable exception) — ассоциирует исключение с вызывающим исключением. Возвращает ссылку на исключение.
- void printStackTrace() — отображает трассировку стека
- void printStackTrace(PrintStream stream) — посылает трассировку стека в заданный поток
- void printStackTrace(PrintWriter stream) — посылает трассировку стека в заданный поток
- void setStackTrace(StackTraceElement elements[]) — устанавливает трассировку стека для элементов (для специализированных приложений)
- String toString() — возвращает объект класса String, содержащий описание исключения.
Самый простой способ — создать класс с конструктором по умолчанию.
// Если этот код работает, его написал Александр Климов,
// а если нет, то не знаю, кто его писал.
package ru.alexanderklimov.exception;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void testMethod() throws HungryCatException{
System.out.println("Возбуждаем HungryCatException из метода testMethod()");
throw new HungryCatException(); // конструктор по умолчанию
}
public void onClick(View view) {
try {
testMethod();
} catch (HungryCatException e) {
e.printStackTrace();
System.out.println("Наше исключение перехвачено");
}
}
class HungryCatException extends Exception{
}
}
Мы создали собственный класс HungryCatException, в методе testMethod() его возбуждаем, а по нажатию кнопки вызываем этот метод. В результате наше исключение сработает.
Создать класс исключения с конструктором, который получает аргумент-строку, также просто.
// Если этот код работает, его написал Александр Климов,
// а если нет, то не знаю, кто его писал.
package ru.alexanderklimov.exception;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void testMethod() throws HungryCatException {
System.out.println("Возбуждаем HungryCatException из метода testMethod()");
throw new HungryCatException(); // конструктор по умолчанию
}
public void testMethod2() throws HungryCatException {
System.out.println("Возбуждаем HungryCatException из метода testMethod2()");
throw new HungryCatException("Создано во втором методе");
}
public void onClick(View view) {
try {
testMethod();
} catch (HungryCatException e) {
e.printStackTrace();
System.out.println("Наше исключение перехвачено");
}
try {
testMethod2();
} catch (HungryCatException e) {
e.printStackTrace();
}
}
class HungryCatException extends Exception {
HungryCatException() {
}
HungryCatException(String msg) {
super(msg);
}
}
}
Ещё вариант. Добавим также метод toString().
class CustomException extends Exception {
String message;
CustomException(String str) {
message = str;
}
public String toString() {
return ("Custom Exception Occurred: " + message);
}
}
// где-то вызываем
try {
throw new CustomException("This is a custom message");
} catch (CustomException e) {
System.out.println(e);
}
Теперь класс содержит два конструктора. Во втором конструкторе используется конструктор родительского класса с аргументом String, вызываемый ключевым словом super.
Перехват произвольных исключений
Можно создать универсальный обработчик, перехватывающий любые типы исключения. Осуществляется это перехватом базового класса всех исключений Exception:
cacth(Exception e) {
Log.w("Log", "Перехвачено исключение");
}
Подобная конструкция не упустит ни одного исключения, поэтому её следует размещать в самом конце списка обработчиков, во избежание блокировки следующих за ней обработчиков исключений.
Основные правила обработки исключений
Используйте исключения для того, чтобы:
- обработать ошибку на текущем уровне (избегайте перехватывать исключения, если не знаете, как с ними поступить)
- исправить проблему и снова вызвать метод, возбудивший исключение
- предпринять все необходимые действия и продолжить выполнение без повторного вызова действия
- попытаться найти альтернативный результат вместо того, который должен был бы произвести вызванный метод
- сделать все возможное в текущем контексте и заново возбудить это же исключение, перенаправив его на более высокий уровень
- сделать все, что можно в текущем контексте, и возбудить новое исключение, перенаправив его на более высокий уровень
- завершить работу программы
- упростить программу (если используемая схема обработки исключений делает все только сложнее, значит, она никуда не годится)
- добавить вашей библиотеке и программе безопасности