Рубрики
Без рубрики

Цепные исключения в Java

В этом уроке мы рассмотрим тему цепных исключений в Java на основе примеров кода.

Автор оригинала: Shubham Aggarwal.

1. Обзор

В этой статье мы очень кратко рассмотрим, что такое Exception , и подробно обсудим цепные исключения в Java.

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

2. Цепные Исключения

Цепочка Исключение помогает определить ситуацию, в которой одно исключение вызывает другое Исключение в приложении.

Например, рассмотрим метод, который вызывает исключение ArithmeticException из-за попытки деления на ноль, но фактической причиной исключения была ошибка ввода-вывода, из-за которой делитель был равен нулю.Метод вызовет ArithmeticException вызывающему объекту. Вызывающий абонент не будет знать о фактической причине Исключения . В таких ситуациях используется цепочка Исключение .

Эта концепция была введена в JDK 1.4.

Давайте посмотрим, как цепные исключения поддерживаются в Java.

3. Бросаемый класс

Класс Throwable имеет некоторые конструкторы и методы для поддержки цепных исключений. Во-первых, давайте посмотрим на конструкторов.

  • Throwable(Throwable cause) Throwable имеет один параметр, который указывает фактическую причину Исключения .
  • Throwable(String desc, Throwable cause) этот конструктор также принимает описание Исключения с фактической причиной Исключения .

Далее давайте рассмотрим методы, предоставляемые этим классом:

  • getCause() метод – Этот метод возвращает фактическую причину, связанную с текущим Исключением .
  • initCause() метод – Он устанавливает основную причину с вызовом Исключения .

4. Пример

Теперь давайте рассмотрим пример, в котором мы установим ваше собственное описание Exception и создадим цепочку Exception :

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());
        }
    }    
}

Как и предполагалось, это приведет к:

Caught: java.lang.ArithmeticException: Top Level Exception.
Actual cause: java.io.IOException: IO cause.

5. Почему Цепные Исключения?

Нам нужно связать исключения в цепочку, чтобы сделать журналы читаемыми. Давайте напишем два примера. Во-первых, без цепочек исключений, а во-вторых, с цепочками исключений. Позже мы сравним, как ведут себя журналы в обоих случаях.

Для начала мы создадим ряд исключений:

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");
    }
}

В приведенном выше примере журналы будут выглядеть следующим образом:

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)

5.2. С Цепью

Далее, давайте напишем пример с цепочкой наших пользовательских исключений:

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

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

В этой статье мы рассмотрели концепцию цепных исключений.

Реализацию всех примеров можно найти в проекте Github – это проект на основе Maven, поэтому его должно быть легко импортировать и запускать как есть.