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 throws
para 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
Runnable
en elThread
marco, 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
run
mé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
Runnable
interfaz 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
Runnable
es 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
Callable
lugar, puede usar un , enviándolo a unExecutorService
y esperando el resultadoFutureTask.isDone()
devuelto por elExecutorService.submit()
.Cuando
isDone()
devuelve verdadero, llamasFutureTask.get()
. Ahora, siCallable
ha lanzado unException
,FutureTask.get()
también lanzará unException
y 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étodocatch
llame; 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
Thread
objetivo, no lo useRunnable
. Por ejemplo, quizásCallable
sea 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 aRuntimeException
y 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
Runnable
Java 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
,BiFunction
y 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,
Runnable
es representativo de cualquier interfaz funcional que no declara excepciones, o declara excepciones demasiado limitadas para el caso de uso en cuestión.Runnable
algún lugar y podría reemplazarloRunnable
con otra cosa.Runnable
conCallable<Void>
. Básicamente lo mismo, pero permite lanzar excepciones; y tiene que hacerloreturn null
al final, lo cual es una leve molestia.Runnable
con su propia costumbre@FunctionalInterface
que 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
RuntimeException
clase en lugar de laException
clase.fuente