Служебный класс, который повторно выбрасывает бросаемый как непроверенный?

Я перехватываю все метания в методе обертки модульного теста, чтобы сбросить некоторые данные во внешней системе. Я хочу повторно выдать исходное исключение, когда это будет сделано, и я использую этот фрагмент кода, чтобы сделать это:

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) могу помочь тебе. Там вы можете определить глобальный обработчик исключений для всех возникающих исключений.

Другие вопросы по тегам