¿Qué es una excepción suprimida?

76

Un comentario (del usuario soc ) sobre una respuesta a una pregunta sobre la optimización de la llamada de cola mencionó que Java 7 tiene una nueva característica llamada "excepciones suprimidas", debido a "la adición de ARM" (¿soporte para CPU ARM?).

¿Qué es una "excepción suprimida" en este contexto? En otros contextos, una "excepción suprimida" sería una excepción que se detecta y luego se ignora (rara vez es una buena idea); esto es claramente algo diferente.

Raedwald
fuente
No veo ninguna mención de ello en la descripción de "Mejoras del lenguaje de programación Java" download.oracle.com/javase/7/docs/technotes/guides/language/…
Raedwald
18
ARM significa Gestión automática de recursos, por ejemplo, infoq.com/news/2010/08/arm-blocks
daniel kullmann
5
ARM, en este contexto, es el antiguo nombre de try-with-resources. Dejaron de usar ARM y comenzaron a usar try-with-resources en algún momento antes del lanzamiento de Java 7. Y @danielkullmann tiene razón en lo que significa ARM
Brad Cupit

Respuestas:

55

Creo que el comentarista se refiere a una excepción que se ignora parcialmente cuando se lanza dentro del finallybloque implícito de un bloque try-with-resources , en el contexto de una excepción existente que se lanza desde el trybloque:

Se puede lanzar una excepción desde el bloque de código asociado con la instrucción try-with-resources. En el ejemplo writeToFileZipFileContents, se puede lanzar una excepción desde el bloque try, y se pueden lanzar hasta dos excepciones desde la declaración try-with-resources cuando intenta cerrar los objetos ZipFile y BufferedWriter. Si se lanza una excepción desde el bloque try y una o más excepciones se lanzan desde la declaración try-with-resources, entonces esas excepciones lanzadas desde la declaración try-with-resources se suprimen y la excepción lanzada por el bloque es la única que arroja el método writeToFileZipFileContents. Puede recuperar estas excepciones suprimidas llamando al método Throwable.getSuppressed desde la excepción lanzada por el bloque try.

(Eso es citar una sección llamada "Excepciones suprimidas" de la página vinculada).

Jon Skeet
fuente
2
Llamada API pertinente: download.oracle.com/javase/7/docs/api/java/lang/…
Raedwald
@Raedwald: Sobre todo, sí, eso creo.
Jon Skeet
6
@JonSkeet @Raedwald: Creo que esta respuesta no tiene en cuenta que las excepciones suprimidas existían antes de Java 7 (no estoy hablando de excepciones ignoradas ): si un finallybloque lanza una excepción cuando el trybloque también lanzó una excepción, la excepción original de la tryel bloque se pierde o se "suprime" (consulte http://accu.org/index.php/journals/236 para obtener más información). Java 7 acaba de agregar un método conveniente para almacenar la excepción del finallybloque porque finallyse genera implícitamente mediante try-with-resources.
JBert
5
Pero un punto a tener en cuenta es que si proporcionamos explícitamente el bloqueo final en la declaración try-with-resource y se lanza una excepción, entonces tiene prioridad sobre las excepciones lanzadas desde el bloque try o try-with-resource.
Aniket Thakur
63

Para aclarar la cita en la respuesta de Jon, solo se puede lanzar una excepción por un método (por ejecución) pero es posible, en el caso de a try-with-resources, que se generen múltiples excepciones. Por ejemplo, uno podría lanzarse al bloque y otro podría lanzarse desde el implícito finallyproporcionado por try-with-resources.

El compilador tiene que determinar cuál de estos lanzará "realmente". Elige lanzar la excepción generada en el código explícito (el código en el trybloque) en lugar de la que arroja el código implícito (el finallybloque). Por lo tanto, las excepciones lanzadas en el bloque implícito se suprimen (ignoran). Esto solo ocurre en el caso de múltiples excepciones.

Juan B
fuente
1
Por lo tanto, las excepciones suprimidas son una consecuencia de la nueva función que significa que ya no necesitamos escribir cláusulas try... engorrosas finallyal abrir e close()ingresar archivos: stackoverflow.com/questions/3305405/…
Raedwald
@JohnB ¿Pero tenemos la opción de constructor de Exception (anotherExcetion e) rit?
Kanagavelu Sugumar
3
@KanagaveluSugumar El Exception(Exception cause)constructor se usa para envolver una excepción causante en otra que podría ser más descriptiva. Sin embargo, en este caso estamos hablando de dos excepciones distintas para las que no existe una relación causal. La excepción A no causó la excepción B, por lo que no tendría sentido envolver una en la otra. Además, está asumiendo que el codificador está lanzando explícitamente la segunda excepción y tiene acceso a la primera. Ese no sería el caso si ambos fueran lanzados por llamadas de biblioteca.
John B
1
@JohnB Creo que tu declaración es incorrecta. "El compilador tiene que determinar cuál de estos lanzará" realmente ". Elige lanzar la excepción generada en el código explícito (el código en el bloque try)" Pero el compilador elegirá sólo la excepción final y la excepción try será suprimida.
Kanagavelu Sugumar
1
@KanagaveluSugumar Según documentación:If an exception is thrown from the try block and one or more exceptions are thrown from the try-with-resources statement, then those exceptions thrown from the try-with-resources statement are suppressed
John B
21

Antes de Java7; Hay excepciones en el código, pero se ignoraron de alguna manera.

p.ej)

public class SuppressedExceptions {
  public static void main(String[] args) throws Exception {
    try {
        callTryFinallyBlock();
    } catch (Exception e) {
        e.printStackTrace(); **//Only Finally Exception is Caught**
    }
  }

  private static void callTryFinallyBlock() throws Exception {
    try 
    {
        throw new TryException(); **//This is lost**
    }
    finally
    {
        FinallyException fEx = new FinallyException();
        throw fEx;
    }
  }
}

class TryException extends Exception {
}

class FinallyException extends Exception {
}

Se agregaron un nuevo constructor y dos nuevos métodos a la clase Throwable en JDK 7. Estos son los siguientes:

Throwable.getSupressed(); // Returns Throwable[]
Throwable.addSupressed(aThrowable);

con este nuevo enfoque, también podemos manejar las excepciones suprimidas.

public class SuppressedExceptions {
  public static void main(String[] args) throws Exception {
    try {
        callTryFinallyBlock();
    } catch (Exception e) {
        e.printStackTrace();
        for(Throwable t: e.getSuppressed())
        {
            t.printStackTrace();
        }
    }
  }

  private static void callTryFinallyBlock() throws Exception {
    Throwable t = null;
    try 
    {
        throw new TryException();
    }
    catch (Exception e) {
        t = e;
    }
    finally
    {
        FinallyException fEx = new FinallyException();
        if(t != null)fEx.addSuppressed(t);
        throw fEx;
    }
  }
}

class TryException extends Exception {
}

class FinallyException extends Exception {
}

En Java7 try-with-resources; la excepción en AutoCloseable :: close () se agrega como excepción suprimida por defecto junto con la excepción try.

También consciente de que esto es diferente de las excepciones encadenadas (se introdujeron con JDK 1.4 y estaban destinadas a hacer posible rastrear fácilmente las relaciones causales entre excepciones).

Kanagavelu Sugumar
fuente
11

Concediendo el siguiente código:

public class MultipleExceptionsExample {

   static class IOManip implements Closeable{
       @Override
       public void close() {
           throw new RuntimeException("from IOManip.close");
       }
   }

   public static void main(String[] args) {
       try(IOManip ioManip = new IOManip()){
           throw new RuntimeException("from try!");
       }catch(Exception e){
           throw new RuntimeException("from catch!");
       }finally{
           throw new RuntimeException("from finally!");
       }
   }
}

Con todas las líneas obtendrás: java.lang.RuntimeException: from finally!

Eliminando el finallybloque obtendrás:java.lang.RuntimeException: from catch!

Eliminando el catchbloque obtendrás:

Exception in thread "main" java.lang.RuntimeException: from try!
    Suppressed: java.lang.RuntimeException: from IOManip.close
Adil
fuente
9

Las excepciones suprimidas son excepciones adicionales que ocurren dentro de una declaración try-with-resources ( introducida en Java 7 ) cuando los AutoCloseablerecursos están cerrados. Debido a que pueden ocurrir múltiples excepciones al cerrar AutoCloseablerecursos, las excepciones adicionales se adjuntan a una excepción principal como excepciones suprimidas .

Al observar el código de bytes de un fragmento de código de muestra try-with-resources, se utilizan manejadores de excepciones JVM estándar para acomodar la semántica try-with-resources.

Dan Cruz
fuente
0

También puede suprimir Excepciones en Java 6 (un pequeño truco involucrado),

Creé una utilidad que maneja de forma transparente la supresión de excepciones en Java 1.6 y Java 1.7. Puedes encontrar la implementación aquí

Todo lo que necesitas es llamar:

public static <T extends Throwable> T suppress(final T t, final Throwable suppressed) 

para suprimir una excepción, y

public static Throwable [] getSuppressed(final Throwable t) {

para obtener las excepciones suprimidas de una excepción, en caso de que alguien todavía use Java 1.6

usuario2179737
fuente
0

ARM - Gestión automática de recursos (introducido desde Java 7)

Tome un ejemplo muy simple

static String readFirstLineFromFileWithFinallyBlock(String path)
                                                     throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(path));
    try {
        return br.readLine();
    } finally {
        if (br != null) br.close();
    }
}

Ahora, si la readLine()función arroja Exception y luego incluso la close()función [en el bloque finalmente] arroja una excepción, entonces se le da más prioridad a la última y se la devuelve a la función que llama. En este caso elException thrown by the readLine() method is ignored/suppressed . Puede encadenar la excepción causante en su excepción y volver a lanzar su excepción desde el bloqueo final.

Dado java 7que se ha proporcionado funcionalidad para recuperar excepciones suprimidas. Puede llamar a la public final java.lang.Throwable[] getSuppressed()función en el objeto arrojadizo capturado para ver las Excepciones suprimidas.

Por ejemplo.

static String readFirstLineFromFileWithFinallyBlock(String path)
        throws Exception {
    try (BufferedReader br = new BufferedReader(new FileReader(path));) {
        return br.readLine();
    }
}

Ahora, si br.readLine();se lanza una línea Exception1y luego digamos que Exception2se lanza mientras se cierra el recurso [Imagine que esto sucede en un bloque final implícito que crea la instrucción try-with-resource], entonces Exception1 suprime Exception2.

Algunos puntos a tener en cuenta aquí:

  1. Si el bloque try-with-resource arroja una excepción, es decir, mientras se crea una instancia del recurso, el bloque try no se ejecutará y se lanzará la misma excepción.
  2. Si la creación de instancias del recurso es exitosa, el bloque try lanza una excepción y se lanza una excepción al cerrar el recurso, luego la excepción lanzada mientras se cierra el recurso es suprimida por la excepción lanzada desde el bloque try.
  3. Si proporciona un bloque final explícito y se lanza una excepción desde ese bloque, se suprimirán todas las demás excepciones. (Este bloque finalmente explícito se ejecuta después de que se cierran los recursos)

He compilado la mayoría de los escenarios posibles con fragmentos de código y salida en la siguiente publicación.

Excepciones suprimidas en java 7

Espero que ayude.

Aniket Thakur
fuente
1
Sin embargo, en este caso, el Exceptionque se origina en el bloque try {} no se suprimirá automáticamente. El programador puede optar por hacerlo, pero usted no lo ha hecho. Solo try-with-resources, cuando sea necesario, suprimirá las excepciones automáticamente. Y cuando lo haga, será la excepción de su bloqueo final equivalente lo que se suprimirá.
Martin Andersson
1
@MartinAndersson Tienes razón. Tuve algo de confusión cuando escribí la respuesta. Espero que la respuesta editada proporcione mejores conocimientos.
Aniket Thakur
-1

Creo que esto tiene que ver con la "facilidad de excepción encadenada". Afectará cómo esta función maneja una excepción a medida que evoluciona el seguimiento de la pila. Con el tiempo, las excepciones que forman parte de un grupo de excepciones encadenadas se pueden suprimir. Consulte la documentación Throwable para obtener más detalles.

Jean-Simon LaRochelle
fuente