( Позднее редактирование: Этот вопрос, мы надеемся, устареет, когда выйдет Java 7, из-за функции "окончательного отбрасывания" , которая, , кажется, будет добавлен .)
Довольно часто я нахожусь в ситуациях, подобных этой:
do some initialization
try {
do some work
} catch any exception {
undo initialization
rethrow exception
}
В C # вы можете сделать это так:
InitializeStuff();
try
{
DoSomeWork();
}
catch
{
UndoInitialize();
throw;
}
Для Java нет хорошей замены, и, поскольку предложение по улучшенной обработке исключений было вырезано из Java 7 , похоже, что в лучшем случае потребуется несколько лет, пока мы не получим нечто подобное. Таким образом, я решил свернуть свое собственное:
( Редактировать: Через полгода, окончательный повторный бросок вернулся , или так кажется.)
public final class Rethrow {
private Rethrow() { throw new AssertionError("uninstantiable"); }
/** Rethrows t if it is an unchecked exception. */
public static void unchecked(Throwable t) {
if (t instanceof Error)
throw (Error) t;
if (t instanceof RuntimeException)
throw (RuntimeException) t;
}
/** Rethrows t if it is an unchecked exception or an instance of E. */
public static <E extends Exception> void instanceOrUnchecked(
Class<E> exceptionClass, Throwable t) throws E, Error,
RuntimeException {
Rethrow.unchecked(t);
if (exceptionClass.isInstance(t))
throw exceptionClass.cast(t);
}
}
Типичное использование:
public void doStuff() throws SomeException {
initializeStuff();
try {
doSomeWork();
} catch (Throwable t) {
undoInitialize();
Rethrow.instanceOrUnchecked(SomeException.class, t);
// We shouldn't get past the above line as only unchecked or
// SomeException exceptions are thrown in the try block, but
// we don't want to risk swallowing an error, so:
throw new SomeException("Unexpected exception", t);
}
private void doSomeWork() throws SomeException { ... }
}
Это немного многословно, ловить Throwable
обычно не одобряется, я не очень рад использовать рефлексию, чтобы просто выбросить исключение, и я всегда чувствую себя немного неловко, когда пишу комментарии "этого не произойдет", но в На практике это работает хорошо (или, кажется, по крайней мере). Что мне интересно, так это:
- Есть ли у меня недостатки в методах помощника rethrow? Какие угловые случаи я пропустил? (Я знаю, что
Throwable
мог быть вызван чем-то настолько серьезным, что мой undoInitialize
потерпит неудачу, но это нормально.)
- Кто-то уже это придумал? Я посмотрел на
ExceptionUtils
Commons Lang, но это делает другие вещи.
Edit:
finally
это не тот дроид, которого я ищу. Мне интересно делать что-то, только когда выдается исключение.
- Да, я знаю, что ловить
Throwable
- это большое нет-нет, но я думаю, что это меньшее зло по сравнению с тем, чтобы иметь три предложения catch (для Error
, RuntimeException
и SomeException
, соответственно) с одинаковыми код.
- Обратите внимание, что я не пытаюсь подавить какие-либо ошибки - идея состоит в том, что любые исключения, сгенерированные в блоке
try
, будут продолжать всплывать через стек вызовов, как только я перезаписал несколько вещей.