1. Обзор
В этой статье мы очень кратко рассмотрим, что такое Exception, и углубимся в обсуждение связанных исключений в Java.
Проще говоря, исключение — это событие, нарушающее нормальный ход выполнения программы. Давайте теперь посмотрим, как именно мы можем сцепить исключения, чтобы получить от них лучшую семантику.
2. Цепочка исключений
Цепочка исключений помогает определить ситуацию, в которой одно исключение вызывает другое исключение в приложении.
Например, рассмотрим метод, который выдает исключение ArithmeticException из-за попытки деления на ноль, но фактической причиной исключения была ошибка ввода-вывода, из-за которой делитель был равен нулю. Метод выдает исключение ArithmeticException вызывающей стороне. . Вызывающий не будет знать о фактической причине исключения. В таких ситуациях используется Chained Exception.
Эта концепция была представлена в JDK 1.4.
Давайте посмотрим, как в Java поддерживаются связанные исключения.
3. Класс Throwable
Класс Throwable имеет несколько конструкторов и методов для поддержки связанных исключений. Во-первых, давайте посмотрим на конструкторы.
Throwable (причина Throwable) — Throwable имеет единственный параметр, который указывает фактическую причину исключения. Throwable(String desc, Throwable Cause) — этот конструктор также принимает описание Exception с фактической причиной Exception.
-
Далее давайте посмотрим на методы, предоставляемые этим классом:
Метод getCause() — этот метод возвращает фактическую причину, связанную с текущим Исключением. Метод initCause () — устанавливает основную причину с вызовом исключения.
-
4. Пример
Теперь давайте рассмотрим пример, в котором мы установим собственное описание исключения и создадим связанное исключение:
Как вы уже догадались, это приведет к:
public class MyChainedException {
public void main(String[] args) {
try {
throw new ArithmeticException("Top Level Exception.")
.initCause(new IOException("IO cause."));
} catch(ArithmeticException ae) {
System.out.println("Caught : " + ae);
System.out.println("Actual cause: "+ ae.getCause());
}
}
}
5. Почему цепные исключения?
Caught: java.lang.ArithmeticException: Top Level Exception.
Actual cause: java.io.IOException: IO cause.
Нам нужно связать исключения в цепочку, чтобы сделать журналы читабельными. Напишем два примера. Во-первых, без цепочки исключений, а во-вторых, со связанными исключениями. Позже мы сравним поведение журналов в обоих случаях.
Для начала мы создадим ряд исключений:
Теперь давайте начнем использовать приведенные выше исключения в примерах кода.
class NoLeaveGrantedException extends Exception {
public NoLeaveGrantedException(String message, Throwable cause) {
super(message, cause);
}
public NoLeaveGrantedException(String message) {
super(message);
}
}
class TeamLeadUpsetException extends Exception {
// Both Constructors
}
5.1. Без цепочки
Давайте напишем пример программы без цепочки наших пользовательских исключений.
В приведенном выше примере логи будут выглядеть так:
public class MainClass {
public void main(String[] args) throws Exception {
getLeave();
}
void getLeave() throws NoLeaveGrantedException {
try {
howIsTeamLead();
} catch (TeamLeadUpsetException e) {
e.printStackTrace();
throw new NoLeaveGrantedException("Leave not sanctioned.");
}
}
void howIsTeamLead() throws TeamLeadUpsetException {
throw new TeamLeadUpsetException("Team Lead Upset");
}
}
5.2. С цепочкой
com.baeldung.chainedexception.exceptions.TeamLeadUpsetException:
Team lead Upset
at com.baeldung.chainedexception.exceptions.MainClass
.howIsTeamLead(MainClass.java:46)
at com.baeldung.chainedexception.exceptions.MainClass
.getLeave(MainClass.java:34)
at com.baeldung.chainedexception.exceptions.MainClass
.main(MainClass.java:29)
Exception in thread "main" com.baeldung.chainedexception.exceptions.
NoLeaveGrantedException: Leave not sanctioned.
at com.baeldung.chainedexception.exceptions.MainClass
.getLeave(MainClass.java:37)
at com.baeldung.chainedexception.exceptions.MainClass
.main(MainClass.java:29)
Далее давайте напишем пример с цепочкой наших пользовательских исключений:
Наконец, давайте посмотрим на журналы, полученные с помощью цепочек исключений:
public class MainClass {
public void main(String[] args) throws Exception {
getLeave();
}
public getLeave() throws NoLeaveGrantedException {
try {
howIsTeamLead();
} catch (TeamLeadUpsetException e) {
throw new NoLeaveGrantedException("Leave not sanctioned.", e);
}
}
public void howIsTeamLead() throws TeamLeadUpsetException {
throw new TeamLeadUpsetException("Team lead Upset.");
}
}
Мы можем легко сравнить показанные журналы и сделать вывод, что связанные исключения приводят к более чистым журналам.
Exception in thread "main" com.baeldung.chainedexception.exceptions
.NoLeaveGrantedException: Leave not sanctioned.
at com.baeldung.chainedexception.exceptions.MainClass
.getLeave(MainClass.java:36)
at com.baeldung.chainedexception.exceptions.MainClass
.main(MainClass.java:29)
Caused by: com.baeldung.chainedexception.exceptions
.TeamLeadUpsetException: Team lead Upset.
at com.baeldung.chainedexception.exceptions.MainClass
.howIsTeamLead(MainClass.java:44)
at com.baeldung.chainedexception.exceptions.MainClass
.getLeave(MainClass.java:34)
... 1 more
6. Заключение
В этой статье мы рассмотрели концепцию связанных исключений.
Реализацию всех примеров можно найти в проекте Github — это проект на основе Maven, поэтому его легко импортировать и запускать как есть.
«