Qu’est-ce qu’une exception supprimée?

Un commentaire (par l’utilisateur soc ) sur une réponse à une question sur l’optimisation des appels de fin indiquait que Java 7 avait une nouvelle fonctionnalité appelée “exceptions supprimées”, en raison de “l’ajout d’ARM” (prise en charge des processeurs ARM?).

Qu’est-ce qu’une “exception supprimée” dans ce contexte? Dans d’autres contextes, une “exception supprimée” serait une exception qui a été interceptée puis ignorée (rarement une bonne idée); c’est clairement quelque chose de différent.

    Je pense que le commentateur fait référence à une exception qui est semi-ignorée lorsqu’elle est lancée dans le bloc finally implicite d’un bloc try-with-resources , dans le contexte d’une exception existante lancée depuis le bloc try :

    Une exception peut être levée à partir du bloc de code associé à l’instruction try-with-resources. Dans l’exemple writeToFileZipFileContents, une exception peut être levée à partir du bloc try, et jusqu’à deux exceptions peuvent être levées à partir de l’instruction try-with-resources lorsqu’elle tente de fermer les objects ZipFile et BufferedWriter. Si une exception est levée à partir du bloc try et qu’une ou plusieurs exceptions sont générées à partir de l’instruction try-with-resources, ces exceptions levées à partir de l’instruction try-with-resources sont supprimées et l’exception émise par le bloc est celle qui est levé par la méthode writeToFileZipFileContents. Vous pouvez récupérer ces exceptions supprimées en appelant la méthode Throwable.getSuppressed à partir de l’exception déclenchée par le bloc try.

    (C’est en citant une section appelée “exceptions supprimées” de la page liée.)

    Pour clarifier la citation dans la réponse de Jon, une seule exception peut être émise par une méthode (par exécution), mais il est possible, dans le cas d’un try-with-resources , de générer plusieurs exceptions. Par exemple, l’un peut être lancé dans le bloc et un autre peut être lancé à partir de l’implicite finally fourni par try-with-resources .

    Le compilateur doit déterminer lequel de ces éléments doit “vraiment” lancer. Il choisit de lancer l’exception déclenchée dans le code explicite (le code dans le bloc try ) plutôt que celui généré par le code implicite (le bloc finally ). Par conséquent, les exceptions lancées dans le bloc implicite sont supprimées (ignorées). Cela ne se produit que dans le cas de plusieurs exceptions.

    Avant Java7; Il y a des exceptions dans le code, mais elles ont été ignorées.

    par exemple)

     public class SuppressedExceptions { public static void main(Ssortingng[] 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 { } 

    Un nouveau constructeur et deux nouvelles méthodes ont été ajoutés à la classe Throwable dans JDK 7. Celles-ci sont les suivantes:

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

    Avec cette nouvelle approche, nous pouvons également gérer ces exceptions supprimées.

     public class SuppressedExceptions { public static void main(Ssortingng[] 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 { } 

    Dans Java7, essayez avec les ressources; l’exception à AutoClosable :: close () est ajoutée en tant qu’exception supprimée par défaut avec l’exception try.

    Sachez également que cela diffère des exceptions chaînées (ont été introduites avec JDK 1.4 et visaient à permettre de suivre facilement les relations de causalité entre les exceptions).

    Les exceptions supprimées sont des exceptions supplémentaires qui surviennent dans une instruction try-with-resources ( introduite dans Java 7 ) lorsque les ressources AutoCloseable sont fermées. Étant donné que plusieurs exceptions peuvent se produire lors de la fermeture des ressources AutoCloseable , des exceptions supplémentaires sont associées à une exception principale en tant qu’exceptions supprimées .

    En regardant le bytecode d’un morceau de code exemple try-with-resources, les gestionnaires d’exceptions JVM standard sont utilisés pour prendre en charge la sémantique try-with-resources.

    En concédant le code ci-dessous:

     public class MultipleExceptionsExample { static class IOManip implements Closeable{ @Override public void close() { throw new RuntimeException("from IOManip.close"); } } public static void main(Ssortingng[] 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!"); } } } 

    Avec toutes les lignes, vous obtiendrez: java.lang.RuntimeException: from finally!

    Enlever finally bloc vous obtiendrez: java.lang.RuntimeException: from catch!

    Enlever le blocage que vous obtiendrez:

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

    Je pense que cela a à voir avec le “système d’exception en chaîne”. Cela affectera la façon dont une exception est gérée par cette fonction à mesure que la trace de la stack évolue. Au fil du temps, les exceptions faisant partie d’un groupe d’exception chaînée peuvent être supprimées. Consultez la documentation Throwable pour plus de détails.

    Vous pouvez également supprimer les exceptions dans Java 6 (une petite astuce impliquée),

    J’ai créé un utilitaire qui gère en toute transparence les exceptions dans Java 1.6 et Java 1.7. Vous pouvez trouver la mise en œuvre ici

    Tout ce dont vous avez besoin est d’appeler:

     public static  T suppress(final T t, final Throwable suppressed) 

    supprimer une exception et

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

    obtenir les exceptions supprimées d’une exception, au cas où quelqu’un utilise encore Java 1.6

    ARM – Gestion automatique des ressources (introduit depuis Java 7)

    Prenons un exemple très simple

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

    Maintenant, si la fonction readLine() lève une exception et que même la fonction close() [in Finalement block] lève une exception, la dernière est plus prioritaire et renvoyée à la fonction appelante. Dans ce cas, l’ Exception thrown by the readLine() method is ignored/suppressed . Vous pouvez chaîner l’exception en cause dans votre exception et relancer votre exception depuis le bloc finally.

    Depuis la fonctionnalité java 7 a été fournie pour récupérer les exceptions supprimées. Vous pouvez appeler la public final java.lang.Throwable[] getSuppressed() sur l’object lanceable intercepté pour afficher les exceptions supprimées.

    Par exemple

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

    Maintenant si br.readLine(); line lève Exception1 et laisse ensuite dire que Exception2 est levé lors de la fermeture de la ressource

    Quelques points à noter ici –

    1. Si le bloc try-with-resource lève une exception, c’est-à-dire que l’instanciation des ressources alors try try ne s’exécutera pas et la même exception sera lancée.
    2. Si l’instanciation de la ressource est réussie, essayez de bloquer une exception et une exception est levée lors de la fermeture de la ressource, puis l’exception levée lors de la fermeture de la ressource est supprimée par l’exception générée par le bloc try.
    3. Si vous fournissez explicitement finalement un bloc et que l’exception est lancée à partir de ce bloc, il supprimera toutes les autres exceptions. (Ce bloc final explicite s’exécute après la fermeture des ressources)

    J’ai compilé la plupart des scénarios possibles avec des extraits de code et des résultats dans l’article suivant.

    Suppression des exceptions dans Java 7

    J’espère que cela pourra aider.