Метод, который я вызываю в run () в классе, который реализует Runnable ), предназначен для генерации исключения.
Но компилятор Java не позволяет мне этого делать и предлагает окружить его командой try / catch.
Проблема в том, что, окружая его попыткой / catch, я делаю этот конкретный run () бесполезным. Я действительно хочу , чтобы бросить это исключение.
Если я укажу throws
для самого run () , компилятор пожалуется на это Exception is not compatible with throws clause in Runnable.run()
.
Обычно я совершенно нормально не позволяю run () генерировать исключение. Но у меня уникальная ситуация, в которой я должен иметь эту функциональность.
Как обойти это ограничение?
Ответы:
Если вы хотите передать класс, который реализуется
Runnable
воThread
фреймворке, вы должны играть по правилам этого фреймворка, см. Ответ Эрнеста Фридман-Хилла, почему делать это в противном случае - плохая идея.Однако у меня есть подозрение, что вы хотите вызвать
run
метод прямо в своем коде, чтобы ваш вызывающий код мог обработать исключение.Ответ на эту проблему прост. Не используйте
Runnable
интерфейс из библиотеки потоков, а вместо этого создайте свой собственный интерфейс с измененной подписью, которая позволяет генерировать проверенное исключение, напримерpublic interface MyRunnable { void myRun ( ) throws MyException; }
Вы даже можете создать адаптер, который преобразует этот интерфейс в реальный
Runnable
(путем обработки отмеченного исключения), подходящий для использования в среде Thread.источник
Runnable
простой интерфейс, и мы можем сделать его самостоятельно. Бесполезно для сценария использования потока, но для передачи различных «исполняемых» фрагментов кода это идеально.Callable
Вместо этого вы можете использовать a , отправив егоExecutorService
и дождавшись результата,FutureTask.isDone()
возвращенногоExecutorService.submit()
.Когда
isDone()
возвращается true, вы звонитеFutureTask.get()
. Теперь, если выCallable
бросилиException
тогдаFutureTask.get()
тоже выброситException
и исходное исключение, к которому вы сможете получить доступ, используяException.getCause()
.источник
Если бы
run()
возникло проверенное исключение, что бы его поймать? У вас нет возможности заключить этоrun()
вызов в обработчик, поскольку вы не пишете код, который его вызывает.Вы можете перехватить проверенное исключение в
run()
методе и сгенерировать неотмеченное исключение (т. Е.RuntimeException
его место ). Это завершит поток с трассировкой стека; возможно, это то, что вам нужно.Если вместо этого вы хотите, чтобы ваш
run()
метод где-то сообщал об ошибке, вы можете просто предоставить метод обратного вызова для вызова блокаrun()
методаcatch
; этот метод мог бы где-то сохранить объект исключения, и тогда ваш заинтересованный поток мог бы найти объект в этом месте.источник
main()
сгенерировать проверенное исключение, что его поймает?» "Еслиrun()
сгенерировать непроверенное исключение, что его поймает?"Да, есть способ выбросить проверенное исключение из
run()
метода, но он настолько ужасен, что я не буду им делиться.Вот что вы можете сделать вместо этого; он использует тот же механизм, что и исключение времени выполнения:
@Override public void run() { try { /* Do your thing. */ ... } catch (Exception ex) { Thread t = Thread.currentThread(); t.getUncaughtExceptionHandler().uncaughtException(t, ex); } }
Как отмечали другие, если ваш
run()
метод действительно является цельюThread
, нет смысла генерировать исключение, потому что оно ненаблюдаемо; генерирование исключения имеет тот же эффект, что и отсутствие исключения (нет).Если это не
Thread
цель, не используйтеRunnable
. Например, возможно,Callable
лучше подходит.источник
t.getUncaughtExceptionHandler().uncaughtException(t, ex);
чтобы передать его в тестовый пример инструментария. Добавление этой одной строки вызывает сбой процесса !. Не знаю почему.Thread.getDefaultUncaughtExceptionHandler()
возвращаетсяnull
? Если нет, то каков результат? Что произойдет, если вместо вызоваuncaughtException()
вы оберните проверенное исключение в aRuntimeException
и выбросите его?Thread.getDefaultUncaughtExceptionHandler()
возвращается лиnull
; в противном случае Android предоставляет значение по умолчанию, чтобы предлагать отчеты и т. д. Но вы можете настроить его на то, что хотите. Здесь больше информации .@FunctionalInterface public interface CheckedRunnable<E extends Exception> extends Runnable { @Override default void run() throws RuntimeException { try { runThrows(); } catch (Exception ex) { throw new RuntimeException(ex); } } void runThrows() throws E; }
источник
Некоторые люди пытаются убедить вас, что вы должны играть по правилам. Слушайте, а подчиняться ли вы, решать вам в зависимости от ситуации. На самом деле «вы ДОЛЖНЫ играть по правилам» (а не «вы ДОЛЖНЫ играть по правилам»). Просто имейте в виду, что если вы не будете играть по правилам, могут быть последствия.
Ситуация применяется не только в случае
Runnable
, но и с Java 8 очень часто в контексте потоков и других мест, где функциональные интерфейсы были введены без возможности иметь дело с проверенными исключениями. Например,Consumer
,Supplier
,Function
,BiFunction
и так далее все были объявлены без средств для борьбы с проверяемыми исключениями.Итак, каковы ситуации и варианты? В приведенном ниже тексте
Runnable
он представляет любой функциональный интерфейс, который не объявляет исключения или объявляет исключения, слишком ограниченные для рассматриваемого варианта использования.Runnable
сами где-то заявили , и можете заменитьRunnable
на что-нибудь другое.Runnable
наCallable<Void>
. По сути то же самое, но с возможностью исключения исключений; и вынужденreturn null
в конце концов, что немного раздражает.Runnable
на свой собственный,@FunctionalInterface
который может выдавать именно те исключения, которые вам нужны.Callable<Void>
вместоRunnable
.RuntimeException
.Вы можете попробовать следующее. Это немного похоже на хакерство, но иногда это то, что нам нужно. Потому что, следует ли проверять исключение или снимать его, определяется его типом, но на практике это должно определяться ситуацией.
@FunctionalInterface public interface ThrowingRunnable extends Runnable { @Override default void run() { try { tryRun(); } catch (final Throwable t) { throwUnchecked(t); } } private static <E extends RuntimeException> void throwUnchecked(Throwable t) { throw (E) t; } void tryRun() throws Throwable; }
Я предпочитаю это,
new RuntimeException(t)
потому что у него более короткая трассировка стека.Теперь вы можете:
executorService.submit((ThrowingRunnable) () -> {throw new Exception()});
Отказ от ответственности: возможность выполнять неконтролируемое приведение таким образом может фактически быть удалена в будущих версиях Java, когда информация о типах обобщенных типов обрабатывается не только во время компиляции, но и во время выполнения.
источник
Ваше требование не имеет смысла. Если вы хотите уведомить вызываемый поток о произошедшем исключении, вы можете сделать это с помощью механизма обратного вызова. Это может быть обработчик, трансляция или что-то еще, о чем вы можете подумать.
источник
Я думаю, что в этом сценарии вам может помочь шаблон слушателя . В случае возникновения исключения в вашем
run()
методе используйте блок try-catch и отправьте в catch уведомление о событии исключения. А затем обработайте событие уведомления. Я думаю, это был бы более чистый подход. Эта ссылка SO дает вам полезный указатель в этом направлении.источник
Самый простой способ - определить собственный объект исключения, который расширяет
RuntimeException
класс вместоException
класса.источник