99
// Выдача исключения для заполнения трассировочных данных try {
throw new ExceptionO; } catch (Exception e) {
for(StackTraceElement ste : e.getStackTraceO)
System.out.pri nt1n(ste.getMethodName()):
}
}
static void g() { f(): } static void h() { g(); } public static void main(String[] args) { f():
System.out.printlnC ");
g():
System, out. printlnC'-- "):
h();
}
} /* Output: f
main
f g
main
f g
h
main *///:-
Повторное возбуждение исключения
В некоторых ситуациях требуется заново возбудить уже перехваченное исклю¬чение; чаще всего это происходит при использовании Exception для перехвата всех исключений. Так как ссылка на текущее исключение уже имеется, вы по¬просту возбуждаете исключение по этой ссылке:
catch(Exception е) {
System, out. pri nti пСБыло возбуждено исключение"): throw e:
}
При повторном возбуждении исключение передается в распоряжение обра¬ботчика более высокого уровня. Все остальные предложения catch текущего блока try игнорируются. Вся информация из объекта, представляющего исклю¬чение, сохраняется, и обработчик более высокого уровня, перехватывающий подобные исключения, сможет ее извлечь.
Если вы просто заново возбуждаете исключение, информация о нем, выво¬димая методом printStackTrace(), будет по-прежнему относиться к месту воз¬никновения исключения, но не к месту его повторного возбуждения. Если вам понадобится использовать новую трассировку стека, вызовите метод fi LLI n S ta с kT г а с e (), который возвращает исключение (объект Throwable), созданное на базе старого с помещением туда текущей информации о стеке. Вот как это выглядит:
// exceptions/Rethrowing.java // Демонстрация метода fillInStackTraceO
public class Rethrowing {
public static void f() throws Exception {
System.out.рппШССоздание исключения в f(D; throw new Exception ("возбуждено из f(D;
}
public static void g() throws Exception { try {
f().
} catch(Exception e) {
System, out. pri ntl n("B методе g(), e printStackTraceO"). e printStackTrace(System.out); throw e,
}
}
public static void h() throws Exception { try {
f():
} catch(Exception e) {
System out.printlnC'B методе h(), e.printStackTrace()"),
e printStackTrace(System.out),
throw (Exception)e fill InStackTraceO,
}
}
public static void main(String[] args) { try {
go.
} catch(Exception e) {
System, out pri ntl n( "main- printStackTraceO"). e.printStackTrace(System out);
}
try {
hO.
} catch(Exception e) {
System out.printlnCmairr printStackTraceO"); e printStackTrace(System out);
}
}
} /* Output
Создание исключения в fO
java lang Exception thrown from f()
at Rethrowing.f(Rethrowing.java 7) at Rethrowing g(Rethrowing java:11) at Rethrowi ng.mai n(Rethrowi ng.java:29) main. printStackTraceO
java.lang.Exception: thrown from f() продолжение &
at Rethrowing.f(Rethrowing.java.7) at Rethrowing.g(Rethrowing java.11) at Rethrowing.main(Rethrowing.java 29) Создание исключения в f() В методе h(). e.printStackTraceO java.lang.Exception, thrown from f()
at Rethrowi ng.f(Rethrowi ng.java•7) at Ret h rowi ng. h (Reth rowi ng. j a va: 20) at Rethrowing main(Rethrowing.java-35) main- printStackTraceO java lang.Exception: thrown from f()
at Ret h rowi ng. h (Ret h rowi ng. j a va • 24) at Rethrowi ng.mai n(Rethrowi ng.java:35)
*///:-
Строка с вызовом fiUInStackTrace() становится новой точкой выдачи исклю¬чения.
Выдаваемое исключение также может отличаться от исходного. В этом слу¬чае эффект получается примерно таким же, как при использовании fillln- StackTrace() — информация о месте зарождения исключения теряется, а остает¬ся информация, относящаяся к новой команде throw.
//: exceptions/RethrowNew java // Повторное возбуждение объекта, // отличающегося от первоначального
class OneException extends Exception {
public OneException(String s) { super(s); }
}
class TwoException extends Exception {
public TwoException(String s) { super(s), }
}
public class RethrowNew {
public static void f() throws OneException {
System.out printin("создание исключения в f(D; throw new OneException("из f()");
}
public static void main(String[] args) { try {
try {
f().
} catch(OneException e) {
System out.printin(
"Во внутреннем блоке try.
e printStackTraceO"). .
e.printStackTrace(System.out);
throw new TwoException("из внутреннего блока try"),
}
} catch(TwoException e) {
System.out.printin(
"Во внешнем блоке try, e.printStackTraceO"), e.printStackTrace(System.out),
}
}
создание исключения в f()
Во внутреннем блоке try, е.printStackTraceO
OneException- thrown from fO
at RethrowNew.f(RethrowNew.java•15) at Reth rowNew.ma i n(Reth rowNew.j ava•20) Во внешнем блоке try, e.printStackTraceO TwoException из внутреннего блока try
at RethrowNew main(RethrowNew.java 25)
*///.-
О последнем исключении известно только то, что оно поступило из внутрен¬него блока try, но не из метода f().
Вам никогда не придется заботиться об удалении предыдущих исключений, и исключений вообще. Все они являются объектами, созданными в общей куче оператором new, и сборщик мусора уничтожает их автоматически.
Цепочки исключений
Зачастую необходимо перехватить одно исключение и возбудить следующее, не потеряв при этом информации о первом исключении — это называется цепоч¬кой исключений (exception chaining). До выпуска пакета JDK 1.4 программистам приходилось самостоятельно писать код, сохраняющий информацию о преды¬дущем исключении, однако теперь конструкторам всех подклассов Throwable может передаваться объект-причина (cause). Предполагается, что причиной яв¬ляется изначальное исключение и передача ее в новый объект обеспечивает трассировку стека вплоть до самого его начала, хотя при этом создается и воз¬буждается новое исключение.
Интересно отметить, что единственными подклассами класса Throwable, при¬нимающими объект-причину в качестве аргумента конструктора, являются три основополагающих класса исключений: Error (используется виртуальной маши¬ной (JVM) для сообщений о системных ошибках), Exception и RuntimeException. Для организации цепочек из других типов исключений придется использовать метод initCause(), а не конструктор.
Следующий пример демонстрирует динамическое добавление полей в объ¬ект DynamicFields во время работы программы: