Чи є спосіб викинути виняток без додавання декларації 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.