¿Hay alguna forma de lanzar una excepción sin agregar la declaración throws?

81

Tengo la siguiente situación.

Tengo una clase Java que hereda de otra clase base y anula un método. El método base no arroja excepciones y, por lo tanto, no tiene throws ...declaración.

Ahora mi propio método debería poder lanzar una excepción, pero tengo la opción de

  • Trague la excepción
  • Agregar una declaración de lanzamientos

Ambos no son satisfactorios porque el primero ignoraría silenciosamente la excepción (de acuerdo, podría realizar algunos registros) y el segundo generaría errores del compilador debido a los diferentes encabezados de métodos.

public class ChildClass extends BaseClass {

        @Override 
        public void SomeMethod() {
            throw new Exception("Something went wrong");
        }
}
Jürgen Steinblock
fuente

Respuestas:

99

Puede lanzar excepciones sin marcar sin tener que declararlas si realmente lo desea. Las excepciones no marcadas se extienden RuntimeException. Los Throwables que se extienden Errortampoco están marcados, pero solo deben usarse para problemas completamente imposibles de manejar (como un código de bytes no válido o falta de memoria).

Como caso específico, se agregó Java 8 UncheckedIOExceptionpara envolver y volver a lanzar IOException.

OrangeDog
fuente
1
Funciona muy bien, tengo que volver a lanzar una RuntimeException porque la excepción proviene de otro método pero funciona muy bien, gracias.
Jürgen Steinblock
42

Aquí hay un truco:

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!"));
    }
}
Ing.Fouad
fuente
¿Me pregunto cómo funciona esto? Investigaré un poco, pero ¿tiene algún recurso que pueda ayudarme? :-)
holmicz
T inferido como RuntimeException. Respondido aquí stackoverflow.com/questions/41380656/… y aquí stackoverflow.com/questions/31316581/…
seenimurugan
1
Truco impresionante! Este truco también se puede aplicar en la expresión / bloque lambda, para permitir asignar el método de excepción comprobada a la interfaz SAM sin ninguna throwsdeclaración.
JasonMing
tiene la ventaja extra extra añadida de no tener que lidiar con inseguros.
lscoughlin
¿Por qué necesita el parámetro ficticio? Además, ¿podría funcionar esto sin el método genérico?
Kiruahxh
28

Una tercera opción es optar por no participar en la comprobación de excepciones (como la propia API estándar tiene que hacer a veces) y envolver la excepción marcada en un RuntimeException:

throw new RuntimeException(originalException);

Es posible que desee utilizar una subclase más específica de RuntimeException.

Michael Borgwardt
fuente
10

Solo quiero agregar una respuesta alternativa, puramente como un FYI :

Sí, hay una manera de lanzar una excepción marcada sin agregar la throwsdeclaración, usando la sun.misc.Unsafeclase. Esto se describe en la siguiente publicación del blog:

Lanzar una excepción marcada de un método sin declararlo

Código de muestra:

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);
  }
}

Como sea, esto no es recomendable. Es mejor incluir una excepción sin marcar como se describe en algunas de las otras respuestas.

dogbane
fuente
3
Hay una razón por la que llaman a esa clase Unsafe.
OrangeDog
4

¿Por qué no lanza una excepción sin marcar? Esto no tiene que ser declarado.

Dos alternativas son

  • envolver con una excepción marcada con una no marcada.
  • no deje que el compilador sepa que está lanzando una excepción marcada, por ejemplo, Thread.currentThread (). stop (e);
  • En Java 6, puede volver a generar la excepción si es así finaly el compilador sabe qué excepciones comprobadas puede haber detectado.
  • En Java 7, puede volver a generar una excepción si es efectivamente final, es decir, no la cambia en el código.

El último es más útil cuando lanza una excepción de verificación en su código y la captura en su código de llamada, pero las capas intermedias no saben nada sobre la excepción.

Peter Lawrey
fuente
El segundo método también es interesante. Pero por el momento, cerrar la excepción es exactamente lo que necesito.
Jürgen Steinblock
@OrangeDog, ya que ha leído esto, ¿puede decirme cuál es la diferencia entre usar stop () en el hilo actual y lanzar una excepción envuelta? ;)
Peter Lawrey
"el siguiente método es idéntico en comportamiento a la operación de lanzamiento de Java, pero elude los intentos del compilador de garantizar que el método de llamada haya declarado todas las excepciones comprobadas que puede generar" ¿cómo es mejor ajustar la excepción?
Peter Lawrey
"Detener un subproceso hace que se desbloqueen todos los monitores que ha bloqueado. Si alguno de los objetos previamente protegidos por estos monitores estaba en un estado inconsistente, otros subprocesos ahora pueden ver estos objetos en un estado inconsistente. [...] A diferencia de otras excepciones no [...] comprobadas, el usuario no tiene ninguna advertencia de que su programa puede estar dañado ".
OrangeDog
4

Sí, hay un por qué, pero no se recomienda en absoluto que pueda usar:

Paquete inseguro de Java

getUnsafe().throwException(new IOException());

Este método arroja una excepción marcada, pero su código no está obligado a capturarlo o volver a lanzarlo. Como excepción de tiempo de ejecución.

Ahmad Al-Kurdi
fuente
2

Aquí hay un ejemplo para interceptar excepciones marcadas y envolverlas en una excepción no marcada:

public void someMethod() {
   try {
      doEvil();
   }
   catch (IOException e)
   {
       throw new RuntimeException(e);
   }
}
Jason S
fuente
-1

puede detectar la excepción con el bloque try-catch en su método anulado. entonces no necesitas declarar throws- statement.

Erhan Bagdemir
fuente
2
claro, pero luego me tragaría la excepción, que es exactamente lo contrario de lo que quiero lograr;)
Jürgen Steinblock
-1

Puede usar cualquier excepción derivada de RuntimeException o RuntimeException en sí

o

use un bloque de prueba para el código de lanzamiento de excepciones y manipúlelo allí

fmucar
fuente