Un método al que estoy llamando en run () en una clase que implementa Runnable ) está diseñado para lanzar una excepción.
Pero el compilador de Java no me deja hacer eso y sugiere que lo rodee con try / catch.
El problema es que rodeándolo con un try / catch hago que ese run () en particular sea inútil. Yo no quiero tirar esa excepción.
Si especifico throwspara run () en sí, el compilador se queja de que Exception is not compatible with throws clause in Runnable.run().
Por lo general, estoy totalmente de acuerdo con no dejar que run () arroje una excepción. Pero tengo una situación única en la que debo tener esa funcionalidad.
¿Cómo puedo solucionar esta limitación?

Respuestas:
Si desea pasar una clase que se implementa
Runnableen elThreadmarco, entonces debe seguir las reglas de ese marco, consulte la respuesta de Ernest Friedman-Hill por qué hacerlo de otra manera es una mala idea.Sin embargo, tengo el presentimiento de que desea llamar al
runmétodo directamente en su código, para que su código de llamada pueda procesar la excepción.La respuesta a este problema es sencilla. No use la
Runnableinterfaz de la biblioteca Thread, sino que cree su propia interfaz con la firma modificada que permite lanzar una excepción marcada, por ejemplopublic interface MyRunnable { void myRun ( ) throws MyException; }Incluso puede crear un adaptador que convierta esta interfaz en real
Runnable(manejando la excepción marcada) adecuado para su uso en el marco de Thread.fuente
Runnablees solo una interfaz simple y podemos crear la nuestra. No es útil para el caso de uso de subprocesos, pero es perfecto para pasar diferentes fragmentos de código "ejecutables".En su
Callablelugar, puede usar un , enviándolo a unExecutorServicey esperando el resultadoFutureTask.isDone()devuelto por elExecutorService.submit().Cuando
isDone()devuelve verdadero, llamasFutureTask.get(). Ahora, siCallableha lanzado unException,FutureTask.get()también lanzará unExceptiony la Excepción original podrá acceder usandoException.getCause().fuente
Si
run()lanzara una excepción marcada, ¿qué la detectaría? No hay forma de incluir esarun()llamada en un controlador, ya que no escribe el código que lo invoca.Puede detectar su excepción marcada en el
run()método y lanzar una excepción sin marcar (es decir,RuntimeException) en su lugar. Esto terminará el hilo con un seguimiento de pila; quizás eso es lo que buscas.Si, en cambio, desea que su
run()método informe el error en algún lugar, entonces puede proporcionar un método de devolución de llamada para que el bloquerun()del métodocatchllame; ese método podría almacenar el objeto de excepción en algún lugar, y luego su hilo interesado podría encontrar el objeto en esa ubicación.fuente
main()arrojara una excepción marcada, ¿qué la atraparía?" "Sirun()lanza una excepción sin marcar, ¿qué la atraparía?"Sí, hay una forma de lanzar una excepción marcada del
run()método, pero es tan terrible que no la compartiré.Esto es lo que puede hacer en su lugar; utiliza el mismo mecanismo que ejercería una excepción de tiempo de ejecución:
@Override public void run() { try { /* Do your thing. */ ... } catch (Exception ex) { Thread t = Thread.currentThread(); t.getUncaughtExceptionHandler().uncaughtException(t, ex); } }Como han señalado otros, si su
run()método es realmente el objetivo de aThread, no tiene sentido lanzar una excepción porque no es observable; lanzar una excepción tiene el mismo efecto que no lanzar una excepción (ninguna).Si no es un
Threadobjetivo, no lo useRunnable. Por ejemplo, quizásCallablesea más adecuado.fuente
t.getUncaughtExceptionHandler().uncaughtException(t, ex);para lanzarlo al caso de prueba de instrumentación. Agregar esta línea hace que el proceso se bloquee. No sé por qué.Thread.getDefaultUncaughtExceptionHandler()vuelvenull? Si no es así, ¿cuál es el tipo de resultado? ¿Qué sucede si, en lugar de llamaruncaughtException(), envuelve la excepción marcada en aRuntimeExceptiony la lanza?Thread.getDefaultUncaughtExceptionHandler()regresanull; de lo contrario, Android proporciona un valor predeterminado para ofrecer informes, etc. Pero puede configurarlo para que haga lo que quiera. Hay más información aquí.@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; }fuente
Algunas personas intentan convencerte de que tienes que seguir las reglas. Escuche, pero si obedece, debe decidir usted mismo dependiendo de su situación. La realidad es que "DEBES jugar según las reglas" (no "DEBES seguir las reglas"). Solo tenga en cuenta que si no cumple con las reglas, puede haber consecuencias.
La situación no solo se aplica en la situación de
RunnableJava 8, sino también con mucha frecuencia en el contexto de Streams y otros lugares donde se han introducido interfaces funcionales sin la posibilidad de lidiar con excepciones comprobadas. Por ejemplo,Consumer,Supplier,Function,BiFunctiony así sucesivamente todos han sido declarados sin instalaciones para lidiar con excepciones comprobadas.Entonces, ¿cuáles son las situaciones y las opciones? En el texto siguiente,
Runnablees representativo de cualquier interfaz funcional que no declara excepciones, o declara excepciones demasiado limitadas para el caso de uso en cuestión.Runnablealgún lugar y podría reemplazarloRunnablecon otra cosa.RunnableconCallable<Void>. Básicamente lo mismo, pero permite lanzar excepciones; y tiene que hacerloreturn nullal final, lo cual es una leve molestia.Runnablecon su propia costumbre@FunctionalInterfaceque puede lanzar exactamente las excepciones que desee.Callable<Void>lugar deRunnable.RuntimeException.Puedes probar lo siguiente. Es un truco, pero a veces lo que necesitamos es un truco. Porque, si una excepción debe estar marcada o desmarcada se define por su tipo, pero prácticamente debería estar definida por la situación.
@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; }Prefiero esto
new RuntimeException(t)porque tiene un seguimiento de pila más corto.Ahora puedes hacer:
executorService.submit((ThrowingRunnable) () -> {throw new Exception()});Descargo de responsabilidad: la capacidad de realizar conversiones no verificadas de esta manera podría eliminarse en versiones futuras de Java, cuando la información de tipo genérico se procesa no solo en tiempo de compilación, sino también en tiempo de ejecución.
fuente
Tu requisito no tiene ningún sentido. Si desea notificar al llamado del hilo sobre una excepción que ocurrió, puede hacerlo a través de un mecanismo de devolución de llamada. Esto puede ser a través de un Handler o una transmisión o cualquier otra cosa que se te ocurra.
fuente
Creo que un patrón de escucha podría ayudarte con este escenario. En caso de que ocurra una excepción en su
run()método, use un bloque try-catch y en la captura envíe una notificación de un evento de excepción. Y luego maneje su evento de notificación. Creo que este sería un enfoque más limpio. Este enlace SO le brinda un puntero útil en esa dirección.fuente
La forma más sencilla es definir su propio objeto de excepción que extienda la
RuntimeExceptionclase en lugar de laExceptionclase.fuente