Чи є спосіб викинути виняток без додавання декларації throws?


81

У мене така ситуація.

У мене є клас Java, який успадковується від іншого базового класу і замінює метод. Базовий метод не створює винятків і, отже, не має throws ...декларації.

Тепер мій власний метод повинен мати можливість створити виняток, але я або маю вибір

  • Проковтнути виняток
  • Додайте декларацію броски

І те, і інше не задовольняє, оскільки перший буде мовчки ігнорувати виняток (добре, я міг би виконати деяку реєстрацію), а другий генеруватиме помилки компілятора через різні заголовки методів.

public class ChildClass extends BaseClass {

        @Override 
        public void SomeMethod() {
            throw new Exception("Something went wrong");
        }
}

Відповіді:


99

Ви можете кидати неперевірені винятки без необхідності їх декларувати, якщо ви дійсно хочете. Невизначені винятки поширюються RuntimeException. Провідні джерела, що поширюються Error, також не перевіряються , але їх слід використовувати лише для цілком неможливих проблем (таких як недійсний байт-код або відсутність пам'яті).

Як конкретний випадок, додано Java 8 UncheckedIOExceptionдля обгортання та відновлення IOException.


1
Чудово працює, я повинен відновити RuntimeException, оскільки виняток походить від іншого методу, але він чудово працює, дякую.
Юрген Штейнблок,

42

Ось трюк:

class Utils
{
    @SuppressWarnings("unchecked")
    private static <T extends Throwable> void throwException(Throwable exception, Object dummy) throws T
    {
        throw (T) exception;
    }

    public static void throwException(Throwable exception)
    {
        Utils.<RuntimeException>throwException(exception, null);
    }
}

public class Test
{
    public static void main(String[] args)
    {
        Utils.throwException(new Exception("This is an exception!"));
    }
}

Цікаво, як це працює? Я проведу деякі дослідження, але чи є у вас ресурси, які можуть мені допомогти? :-)
holmicz

T виведено як RuntimeException. Відповів тут stackoverflow.com/questions/41380656 / ... і тут stackoverflow.com/questions/31316581 / ...
seenimurugan

1
Приголомшливий фокус! Цей фокус також може застосовуватися до лямбда-виразу / блоку, щоб дозволити призначати метод перевірених винятків інтерфейсу SAM без будь-яких throwsоголошень.
JasonMing

має додатковий супер додатковий бонус за відсутність необхідності мати справу з небезпечними.
lscoughlin

Навіщо потрібен фіктивний параметр? Крім того, чи могло б це працювати без загального методу?
Kiruahxh

28

Третій варіант - відмовитись від перевірки винятків (подібно до того, як іноді доводиться робити сам Стандартний API) та обертати перевірений виняток у RuntimeException:

throw new RuntimeException(originalException);

Можливо, ви захочете використовувати більш конкретний підклас RuntimeException.


10

Я просто хочу додати альтернативну відповідь, суто як FYI :

Так, існує спосіб викинути перевірений виняток без додавання throwsдекларації, використовуючи sun.misc.Unsafeклас. Це описано в наступному дописі в блозі:

Викиньте перевірений виняток із методу, не оголошуючи його

Зразок коду:

public void someMethod() {
  //throw a checked exception without adding a "throws"
  getUnsafe().throwException(new IOException());
}

private Unsafe getUnsafe() {
  try {
    Field field = Unsafe.class.getDeclaredField("theUnsafe");
    field.setAccessible(true);
    return (Unsafe) field.get(null);
  } catch (Exception e) {
    throw new RuntimeException(e);
  }
}

Однак це не рекомендується. Краще обернути неперевіреним винятком, як зазначено в деяких інших відповідях.


3
Є причина, з якої вони називають цей клас Unsafe.
OrangeDog

4

Чому б вам не викинути неперевірений виняток? Це не потрібно декларувати.

Є дві альтернативи

  • обтікання з перевіреним винятком з неперевіреним.
  • не повідомляйте компілятору, що ви кидаєте перевірений виняток, наприклад Thread.currentThread (). stop (e);
  • У Java 6 ви можете відновити виняток, якщо він є, finalі компілятор знає, які перевірені винятки ви могли виявити.
  • У Java 7 ви можете відновити виняток, якщо він фактично остаточний, тобто ви не змінюєте його в коді.

Пізніший варіант є більш корисним, коли ви додаєте виняток чека у свій код і ловите його у своєму викликовому коді, але шари між ними не знають нічого про виняток.


Другий метод теж цікавий. Але на даний момент обгортання виключення - це саме те, що мені потрібно.
Юрген Штейнблок,


@OrangeDog, оскільки ви це вже прочитали, чи можете ви сказати мені, в чому різниця між використанням stop () у поточному потоці та викиданням загорнутого винятку. ;)
Пітер Лорі

"наступний метод поведінково ідентичний операції кидання Java, але обходить спроби компілятора гарантувати, що викличний метод оголосив усі перевірені винятки, які він може викидати", як обертати виняток краще?
Пітер Лорі

"Зупинка потоку змушує його розблокувати всі монітори, які він заблокував. Якщо будь-який із об'єктів, раніше захищених цими моніторами, перебував у несумісному стані, інші потоки тепер можуть переглядати ці об'єкти в несумісному стані. [...] На відміну від інші неперевірені винятки [...] користувач не попереджає, що його програма може бути пошкоджена. "
OrangeDog

4

Так, є причина, але це взагалі не рекомендується використовувати:

Небезпечний пакет Java

getUnsafe().throwException(new IOException());

Цей метод викидає перевірене виняток, але ваш код не змушує його перехоплювати або відновлювати. Так само, як виняток виконання.


2

Ось приклад для перехоплення перевірених винятків та загортання їх у неперевірений виняток:

public void someMethod() {
   try {
      doEvil();
   }
   catch (IOException e)
   {
       throw new RuntimeException(e);
   }
}

-1

ви можете зловити виняток за допомогою блоку try-catch у вашому методі, який замінено. тоді вам не потрібно оголошувати оператор throws-.


2
звичайно, але тоді я проковтнув би виняток, який якраз протилежний тому, що я хочу отримати;)
Юрген Штейнблок

-1

Ви можете використовувати будь-який виняток, отриманий із RuntimeException або самого RuntimeException

або

використовуйте блок спроб для викиду коду, що кидає, і обробляйте його там

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.