Ответ 1
Метод 1:
Этот пост Алексея Рагозина описывает, как использовать трюк дженериков, чтобы бросить необъявленное проверенное исключение. Из этого сообщения:
public class AnyThrow {
public static void throwUnchecked(Throwable e) {
AnyThrow.<RuntimeException>throwAny(e);
}
@SuppressWarnings("unchecked")
private static <E extends Throwable> void throwAny(Throwable e) throws E {
throw (E)e;
}
}
Трюк полагается на throwUnchecked
"лежащий" компилятору, что тип E
равен RuntimeException
с его вызовом throwAny
. Поскольку throwAny
объявлен как throws E
, компилятор считает, что конкретный вызов может просто бросить RuntimeException
. Разумеется, трюк стал возможным благодаря throwAny
произвольному объявлению E
и слепому кастингу на него, позволяющему вызывающему пользователю решить, к чему его аргумент приписывается - ужасный дизайн при правильном кодировании. Во время выполнения E
erased и не имеет значения.
Как вы отметили, делать такую вещь - огромный взлом, и вы должны хорошо документировать его использование.
Метод 2:
Вы также можете использовать sun.misc.Unsafe
для этой цели. Сначала вы должны реализовать метод, который использует отражение для возврата этого экземпляра класса:
private static Unsafe getUnsafe() {
try {
Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafeField.setAccessible(true);
return (Unsafe)theUnsafeField.get(null);
}
catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
Это необходимо, так как вызов Unsafe.getUnsafe()
обычно генерирует SecurityException
. Когда у вас есть экземпляр Unsafe
, вы можете использовать его ужасающие возможности:
Unsafe unsafe = getUnsafe();
unsafe.throwException(new Exception());
Кредит переходит на этот ответ на сообщение fooobar.com/questions/18702/.... Я думал, что упомянул об этом для полноты, но, вероятно, лучше просто использовать трюк выше, а не разрешать Unsafe
в свой код.
Способ 3:
В комментариях связанного ответа об использовании Unsafe
@bestsss указывает на более простой трюк, используя устаревший метод Thread.stop(Throwable)
:
Thread.currentThread().stop(new Exception());
В этом случае вы бы использовали @SuppressWarnings("deprecation")
и еще раз документ очень яростно. Опять же, я предпочитаю первый трюк за его (относительную) чистоту.