Есть ли способ вызвать исключение без добавления объявления 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.

OrangeDog
источник
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!"));
    }
}
Англ.Fouad
источник
Интересно, как это работает? Я проведу небольшое исследование, но есть ли у вас ресурсы, которые могут мне помочь? :-)
holmicz
T выводится как RuntimeException. Ответил здесь stackoverflow.com/questions/41380656/… и здесь stackoverflow.com/questions/31316581/…
seenimurugan
1
Шикарный трюк! Этот трюк также можно применить к лямбда-выражению / блоку, чтобы разрешить присвоение метода отмеченного исключения интерфейсу SAM без каких-либо throwsобъявлений.
JasonMing
имеет дополнительный супер-дополнительный бонус - вам не придется иметь дело с небезопасными.
lscoughlin
Зачем нужен фиктивный параметр? Кроме того, могло ли это работать без универсального метода?
Kiruahxh 03 авг.2020,
28

Третий вариант - отказаться от проверки исключений (точно так же, как иногда приходится делать самому стандартному API) и обернуть проверенное исключение в RuntimeException:

throw new RuntimeException(originalException);

Возможно, вы захотите использовать более конкретный подкласс RuntimeException.

Майкл Боргвардт
источник
10

Я просто хочу добавить альтернативный ответ, чисто в качестве к сведению :

Да, есть способ сгенерировать проверенное исключение без добавления 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 () в текущем потоке и выдачей обернутого исключения. ;)
Питер Лоури
«следующий метод поведенчески идентичен операции throw в 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

или же

используйте блок try для кода выдачи исключения и обработайте его там

fmucar
источник