Выбрать главу

at Full Constructors g(Ful1 Constructors java:15) at FullConstructors.main(FullConstructors.java 24)

III-

Изменения незначительны — появилось два конструктора, определяющие способ создания объекта MyException. Во втором конструкторе используется конструктор родительского класса с аргументом String, вызываемый ключевым словом super.

В обработчике исключений вызывается метод printStackTrace() класса Throwable (базового для Exception). Этот метод выводит информацию о последо¬вательности вызовов, которая привела к точке возникновения исключения. В нашем примере информация направляется в System.out, но вызов по умолча¬нию направляет информацию в стандартный поток ошибок:

e.printStackTraceO,

Регистрация исключений

Вспомогательное пространство имен java.utiLlogging позволяет зарегистриро¬вать информацию об исключениях в журнале. Базовые средства регистрации достаточно просты:

II exceptions/LoggingExceptions.java // Регистрация исключений с использованием Logger import java.util.logging *; import java.io *;

class LoggingException extends Exception { private static Logger logger =

Logger getLogger("LoggingException"); public LoggingException() {

StringWriter trace = new StringWriter(); printStackTrace(new PrintWriter(trace)), 1ogger.severe(trace.toStri ng()),

public class LoggingExceptions {

public static void main(String[] args) { try {

throw new LoggingException(); } catch(LoggingException e) {

System.err.println("Перехвачено " + e),

}

try {

throw new LoggingExceptionO: } catch(LoggingException e) {

System.err.println("Перехвачено " + e),

} /* Output (85Х match)

Aug 30, 2005 4:02:31 РМ LoggingException <init> SEVERE LoggingException

at LoggingExceptions.main(LoggingExceptions.java:19)

Перехвачено LoggingException

Aug 30, 2005 4.02.31 PM LoggingException <init>

SEVERE LoggingException

at Loggi ngExcepti ons.mai n(Loggi ngExcepti ons.j ava:24)

Перехвачено LoggingException */// -

Статический метод Logger.getLogger() создает объект Logger, ассоциируемый с аргументом String (обычно имя пакета и класса, к которому относятся ошиб¬ки); объект передает свой вывод в System.err. Простейший способ записи ин¬формации в Logger заключается в вызове метода, соответствующего уровню ошибки; в нашем примере используется метод severe(). Нам хотелось бы создать String для регистрируемого сообщения из результатов трассировки стека, но ме¬тод printStackTrace() по умолчанию не создает String. Для получения String необ¬ходимо использовать перегруженную версию printStackTrace() с аргументом java.io.PrintWriter (за подробными объяснениями обращайтесь к главе «Ввод/вы¬вод»). Если передать конструктору PrintWriter объект java.io. StringWriter, для по¬лучения вывода в формате String достаточно вызвать toString().

Подход LoggingException чрезвычайно удобен (вся инфраструктура регистра¬ции встроена в само исключение, и все работает автоматически без вмешательст¬ва со стороны клиента), однако на практике чаще применяется перехват и реги¬страция «сторонних» исключений, поэтому сообщение должно генерироваться в обработчике исключения:

//: exceptions/LoggingExceptions2.java // Регистрация перехваченных исключений, import java.util.logging.*; import java.io.*:

public class LoggingExceptions2 { private static Logger logger =

Logger.getLogger("Loggi ngExcepti ons2"): static void logException(Exception e) {

StringWriter trace = new StringWriter(); e.printStackTrace(new PrintWriter(trace)): 1ogger.severe(trace.toStri ng());

}

public static void main(String[] args) { try {

throw new NullPointerException(); } catch(NullPointerException e) { logException(e):

}

}

} /* Output: (90* match)

Aug 30, 2005 4:07:54 PM LoggingExceptions2 logException

SEVERE: java.lang.NullPointerException продолжение &

at LoggingExceptions2 main(LoggingExceptions2 java:16)

*///.-

На этом процесс создания собственных исключений не заканчивается — ис¬ключение можно снабдить дополнительными конструкторами и элементами:

//: exceptions/ExtraFeatures.java // Дальнейшее расширение классов исключений, import static net.mindview.util.Print.*:

class MyException2 extends Exception { private int x; public MyException2() {} public MyException2(String msg) { super(msg): } public MyException2(String msg, int x) { super(msg): this.x = x:

}

public int valО { return x: } public String getMessageO {

return "Подробное сообщение: "+ x + " " + super getMessageO:

public class ExtraFeatures {

public static void f() throws MyException2 { print("MyException2 в f()"), throw new MyException2():

}

public static void g() throws MyException2 {

System out.println("MyException2 в g()"); throw new MyException2("Возбуждено в g()");

}

public static void h() throws MyException2 {

System out.println("MyException2 в h()"): throw new MyException2("Возбуждено в h()", 47);

}

public static void main(String[] args) { try {

f():

} catch(MyException2 e) {

e.printStackTrace(System.out);

}

try {

g():

} catch(MyException2 e) {

e.printStackTrace(System out):

}

try {

h():

} catch(MyException2 e) {

e.printStackTrace(System.out):

System out.printlnC'e.valO = " + e.valO):

}

}

} /* Output: MyException2 в f()

MyException2: Подробное сообщение: 0 null

at ExtraFeatures.f(ExtraFeatures.java•22)

at ExtraFeatures.main(ExtraFeatures.java.34) MyException2 в g()

MyException2: Подробное сообщение: 0 Возбуждено в g()

at ExtraFeatures.g(ExtraFeatures.java:26) at ExtraFeatures.main(ExtraFeatures.java:39) MyException2: Подробное сообщение: 47 Возбуждено в h() at ExtraFeatures.h(ExtraFeatures.java:30) at ExtraFeatures.main(ExtraFeatures.java:44)

e.valO = 47 *///:-

Было добавлено поле данных х вместе с методом, считывающим его значе¬ние, а также дополнительный конструктор для инициализации х. Переопреде¬ленный метод Throwable.getMessage() выводит более содержательную информа¬цию об исключении. Метод getMessage() для классов исключений — аналог toStringO в обычных классах.

Так как исключение является просто видом объекта, расширение возможно¬стей классов исключений можно продолжить. Однако следует помнить, что все эти программисты, использующие ваши библиотеки, могут попросту проигно¬рировать все «украшения» — нередко программисты ограничиваются провер¬кой типа исключения (как чаще всего бывает со стандартными исключениями Java).

Спецификации исключений

В языке Java желательно сообщать программисту, вызывающему ваш метод, об исключениях, которые данный метод способен возбуждать. Пользователь, вызывающий метод, сможет написать весь необходимый код для перехвата воз¬можных исключений. Конечно, когда доступен исходный код, программист- клиент может пролистать его в поиске предложений throw, но библиотеки не всегда поставляются с исходными текстами. Чтобы библиотека не превраща¬лась в «черный ящик», в Java добавили синтаксис (обязательный для использо¬вания), при помощи которого вы сообщаете клиенту об исключениях, возбуж¬даемых методом, чтобы он сумел правильно обработать их. Этот синтаксис называется спецификацией исключений (exception specification), входит в объяв¬ление метода и следует сразу за списком аргументов.

Спецификация исключений состоит из ключевого слова throws, за которым перечисляются все возможные типы исключений. Примерное определение ме¬тода будет выглядеть так:

void f() throws TooBig. TooSmall. DivZero { //...

Однако запись

void f() { // ...

означает, что метод не вырабатывает исключений. (Кроме исключений, произ¬водных от RuntimeException, которые могут быть возбуждены практически в лю¬бом месте — об этом еще будет сказано.)