Служебный класс, который повторно выбрасывает бросаемый как непроверенный?
Я перехватываю все метания в методе обертки модульного теста, чтобы сбросить некоторые данные во внешней системе. Я хочу повторно выдать исходное исключение, когда это будет сделано, и я использую этот фрагмент кода, чтобы сделать это:
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else if (t instanceof Error) {
throw (Error) t;
} else {
throw new RuntimeException(t);
}
Тем не менее, есть ли какой-либо существующий вызов утилиты, который делает это уже?
(Я ловлю throwables, потому что ошибки AssertionErrors.)
Изменить: Честно говоря, я не хочу оборачивать исключение, поэтому любой трюк, который позволил бы мне бросать любые броски (включая проверенные исключения) без объявления бросков, является приемлемым.
3 ответа
Да, есть способ написать метод, который позволит избежать переноса проверенных исключений. Для этого варианта использования он идеально подходит, хотя вы должны определенно быть очень осторожным с ним, поскольку он может легко запутать непосвященного. Вот:
@SuppressWarnings("unchecked")
public static <T extends Throwable> void sneakyThrow(Throwable t) throws T {
throw (T) t;
}
и вы бы использовали его как
catch (Throwable t) { sneakyThrow(t); }
Как прокомментировал Йоахим Зауэр, в некоторых случаях это помогает убедить компилятор, что строка, вызывающая sneakyThrow
заставляет метод завершаться. Мы можем просто изменить объявленный тип возвращаемого значения:
@SuppressWarnings("unchecked")
public static <T extends Throwable> void sneakyThrow(Throwable t) throws T {
throw (T) t;
}
и используйте это так:
catch (Throwable t) { throw sneakyThrow(t); }
В образовательных целях приятно видеть, что происходит на уровне байт-кода. Соответствующий фрагмент из javap -verbose UncheckedThrower
:
public static <T extends java.lang.Throwable> java.lang.RuntimeException sneakyThrow(java.lang.Throwable) throws T;
descriptor: (Ljava/lang/Throwable;)Ljava/lang/RuntimeException;
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: athrow
Exceptions:
throws java.lang.Throwable
Signature: #13 // <T:Ljava/lang/Throwable;>(Ljava/lang/Throwable;)Ljava/lang/RuntimeException;^TT;
Заметки нет checkcast
инструкция. Метод даже законно заявляет, чтобы бросить любой Throwable
, который является стиранием T
,
У великой библиотеки гуавы есть метод Throwables.propagate(Throwable)
это именно то, что делает ваш код: JavaDoc
Из документа:
Распространяет throwable как есть, если это экземпляр RuntimeException или Error, или же в качестве последнего средства, оборачивает его в RuntimeException, а затем распространяется.
Возможно setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler)
могу помочь тебе. Там вы можете определить глобальный обработчик исключений для всех возникающих исключений.