Сцепленные исключения

Начиная с J2SE 1.4, в подсистему исключений было добавлено новое средство: сцепленные исключения (chained exceptions). Это средство позволяет ассоциировать с одним исключением другое исключение. Второе исключение описывает причину появления первого. Например, представьте ситуацию, когда метод возбуждает исключение ArithmeticException, поскольку была предпринята попытка деления на ноль Однако реальная причина проблемы заключается в ошибке ввода-вывода, что приводит к неправильному делению. И хотя метод должен возбуждать ArithmeticException, так как произошла именно эта ошибка, вы можете также позволить вызывающему коду узнать о том, что в основе лежит ошибка ввода-вывода. Сцепленные исключения позволяют справиться с этой, а также с любой другой ситуацией, в которой присутствуют уровни исключений.

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

Ниже показаны конструкторы.

Throwable(Throwable causeExc)
Throwable(String msg, Throwable causeExc)

В первой форме causeExc — это исключение, послужившее причиной текущего исключения. Если такого нет, возвращается null. Метод initCauseO ассоциирует causeExc с вызывающим исключением и возвращает ссылку на исключение. То есть вы можете вызвать initCause () только однажды для каждого объекта-исключения. Более того, если исключение-причина было установлено конструктором, то вы не можете установить его заново методом initCause ().

Вообще говоря, initCause () используется для установки причины унаследованного класса исключения, которое не поддерживает эти два дополнительных конструктора.

Вот пример, демонстрирующий применение механизма сцепленных исключений:

// Демонстрация сцепленных исключений.
class ChainExcDemo {
static void demoprocО {
// создать исключение
NullPointerException е = new NullPointerException("верхний уровень");
// добавить причину
е.initCause(new ArithmeticException("причина"));
throw е;
}
public static void main(String args[]) {
try {
demoproc();
}
catch(NullPointerException e) {
// отобразить исключение верхнего уровня
System.out.println("Перехвачено: " + е) ;
// отобразить исключение-причину
System.out.println("Исходная причина: " + е. getCause О) ;
}
}
}

Эта программа создает следующий вывод:

Перехвачено: java.lang.NullPointerException: верхний уровень
Исходная причина: java.lang.ArithmeticException: причина

В этом примере исключением верхнего уровня является NullPointerException. К нему добавлено исключение-причина — ArithmeticException. Когда исключение возбуждается из demoproc(), оно перехватывается в main (). Затем исключение верхнего уровня отображается, а за ним следует исключение, лежащее в основе, которое извлекается методом getCause ().

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

Сцепленные исключения не являются вещью, совершенно необходимой в каждой программе. Однако в случаях, когда информация об исключении-причине таки нужна, они представляют собой элегантное решение.