Рейтинговые книги
Читем онлайн Философия Java3 - Брюс Эккель

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 64 65 66 67 68 69 70 71 72 ... 132

}

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 во время работы программы:

//. exceptions/DynamicFields.java // Динамическое добавление полей в класс. // Пример использования цепочки исключений, import static net mindview.util Print *;

class DynamicFieldsException extends Exception {}

public class DynamicFields { private Object[][] fields; public DynamicFields(int initialSize) {

fields = new 0bject[initialSize][2]. for(int i = 0. i < initialSize. i++)

fields[i] = new Object[] { null, null };

}

public String toStringO {

StringBuilder result = new StringBuilderO. . Л

продолжение &

for(Objected obj : fields) {

result.append(obj[0]); result.append("• "); result.append(obj[l]); result.append("n");

}

return result.toStringO;

}

private int hasField(String id) {

for(int i = 0; i < fields.length; i++) if(id.equals(fields[1][0])) return i;

return -1:

}

private int

getFieldNumber(String id) throws NoSuchFieldException { int fieldNum = hasField(id); if(fieldNum == -1)

throw new NoSuchFieldException0; return fieldNum;

}

private int makeField(String id) {

for(int i = 0; i < fields.length; i++) 1f(f1elds[i][0] == null) { fields[1][0] « id; return i;

}

// Пустых полей нет. Добавим новое:

Object[][]tmp = new Object[fields.length + 1][2];

for(int i = 0; i < fields.length; i++)

tmp[i] = fields[i]; for(int i = fields.length; i < tmp.length; i++) tmp[i] = new Object[] { null, null }; fields = tmp;

// Рекурсивный вызов с новыми полями: return makeField(id);

}

public Object

getField(String id) throws NoSuchFieldException { return fields[getFieldNumber(id)][l];

}

public Object setField(String id. Object value)

throws DynamicFieldsException { if(value == null) {

// У большинства исключений нет конструктора.

// принимающего объект-«причину».

// В таких случаях следует использовать

// метод initCauseO, доступный всем подклассам

// класса Throwable.

DynamicFieldsException dfe =

new DynamicFieldsExceptionO; dfe.i ni tCause(new Nul1Poi nterExcepti on О); throw dfe;

}

int fieldNumber = hasField(id); if(fieldNumber == -1)

fieldNumber = makeField(id); Object result = null;

try {

result = getField(id). 11 Получаем старое значение } catchCNoSuchFieldException e) {

// Используем конструктор с «причиной» throw new RuntimeException(e),

}

fields[fieldNumber][l] = value; return result;

}

public static void main(String[] args) {

DynamicFields df = new DynamicFields(3); print(df); try {

df setFieldC'd". "Значение d"); df setField("число", 47); df.setField("4Haio2 48); print(df);

df.setFieldC'd". "Новое значение d"), df setField("4HOio3". 11). printCdf: " + df).

printCdf getField("d")) " + df getFieldCd")); Object field = df setFieldC'd". null). // Исключение } catch(NoSuchFieldException e) {

e printStackTrace(System out); } catch(DynamicFieldsException e) {

e.printStackTrace(System.out);

}

}

} /* Output: null null null: null' null: null d: Значение d число: 47 число2: 48

df- d- Новое значение d число: 47 число:2 48 числоЗ- 11

Значение df .getFieldCd") . Новое значение d Dynami cFi eldsExcepti on

at DynamicFields.setField(DynamicFields.java:64) at DynamicFields main(DynamicFields java:94) Caused by: java.lang.NullPointerException

at DynamicFields.setField(DynamicFields.java 66) )

Каждый объект DynamicFields содержит массив пар Object-Object. Первый объект содержит идентификатор поля (String), а второй объект — значение поля, которое может быть любого типа, кроме неупакованных примитивов. При создании объекта необходимо оценить примерное количество полей. Метод setField() либо находит уже существующее поле с заданным именем, либо создает новое поле и сохраняет значение. Когда пространство для полей заканчивается, метод наращивает его, создавая массив размером на единицу больше и копируя в него старые элементы. При попытке размещения пустой ссылки null метод инициирует исключение DynamicFieldsException, создавая объект нужного типа и передавая методу initCause() в качестве причины исключение NullPointer-Exception.

Для возвращаемого значения метод setField() использует старое значение поля, получая его методом getField(), который может возбудить исключение NoSuchFieldException. Если метод getField() вызывает программист-клиент, то он ответственен за обработку возможного исключения NoSuchFieldException, однако, если последнее возникает в методе setField(), это является ошибкой программы; соответственно, полученное исключение преобразуется в исключение Runtime-Exception с помощью конструктора, принимающего аргумент-причину.

Для создания результата toStringO использует объект StringBuilder. Этот класс будет подробно рассмотрен при описании работы со строками.

Стандартные исключения Java

Класс Java Throwable описывает все объекты, которые могут возбуждаться как исключения. Существует две основные разновидности объектов Throwable (то есть ветви наследования). Тип Error представляет системные ошибки и ошибки времени компиляции, которые обычно не перехватываются (кроме нескольких особых случаев). Тип Exception может быть возбужден из любого метода стандартной библиотеки классов Java или пользовательского метода в случае неполадок при исполнении программы. Таким образом, для программистов интерес представляет прежде всего тип Exception.

Лучший способ получить представление об исключениях — просмотреть документацию JDK. Стоит сделать это хотя бы раз, чтобы получить представление о различных видах исключений, но вскоре вы убедитесь в том, что наиболее принципиальным различием между разными исключениями являются их имена. К тому же количество исключений в Java постоянно растет, и едва ли имеет смысл описывать их в книге. Любая программная библиотека от стороннего производителя, скорее всего, также будет иметь собственный набор исключений. Здесь важнее понять принцип работы и поступать с исключениями сообразно.

Основной принцип заключается в том, что имя исключения относительно полно объясняет суть возникшей проблемы. Не все исключения определены в пакете java.lang, некоторые из них созданы для поддержки других библиотек, таких как util, net и io, как можно видеть из полных имен их классов или из базовых классов. Например, все исключения, связанные с вводом/выводом (I/O), унаследованы от java.io.IOException.

Особый случай: RuntimeException

Вспомним первый пример в этой главе:

if(t == null)

throw new NullPointerExceptionO;

Только представьте, как ужасно было бы проверять таким образом каждую ссылку, переданную вашему методу. К счастью, делать это не нужно — такая проверка автоматически выполняется во время исполнения Java-программы, и при попытке использования null-ссылок автоматически возбуждается Null-PointerException. Таким образом, использованная в примере конструкция избыточна.

1 ... 64 65 66 67 68 69 70 71 72 ... 132
На этой странице вы можете бесплатно читать книгу Философия Java3 - Брюс Эккель бесплатно.
Похожие на Философия Java3 - Брюс Эккель книги

Оставить комментарий