}
}
} /* 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 nulclass="underline" null' nulclass="underline" 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.