Java 7: Gestione delle Suppressed Exceptions nel try-with-resources

DOMANDA:

Cosa sono e come si gestiscono le Suppressed Exceptions in un try-with-resources?



RISPOSTA:

Nei post precedenti abbiamo visto lo statement try-with-resources e come creare oggetti autochiudenti grazie alle novità introdotte con Java 7.

Un particolare comportamento delle eccezioni introdotto con il try-with-resources è quello delle Suppressed Exceptions. Come già intuibile dal nome, sono delle eccezioni soppresse dalla JVM.

Guardiamo subito un esempio di una risorsa AutoCloseable che lancia due eccezioni, una generica Exception in chiusura e una IOException nel metodo faiQualcosa():

package trywithresources;

import java.io.IOException;

public class PrimaRisorsa implements AutoCloseable{
   public PrimaRisorsa() {
      System.out.println("COSTRUISCO LA RISORSA");
   }

   public void faiQualcosa() throws IOException {
      System.out.println("PrimaRisorsa: Faccio qualcosa");
      throw new IOException("Eccezione di faiQualcosa generata da PrimaRisorsa");
   }

   @Override
   public void close() throws Exception {
      System.out.println("CHIUDO PrimaRisorsa");
      throw new Exception("Eccezione di Chiusura generata da PrimaRisorsa");
   }
}



Utilizziamola con una classe di Test:

package trywithresources;

public class TestSuppressedExceptions {
   public static void main(String[] args) {

      try (
         PrimaRisorsa sr = new PrimaRisorsa();
      ) {

         System.out.println("****** START *******");
         sr.faiQualcosa();

      } catch(Exception ex) {
         System.out.println("Eccezione nel try-with-resources:" + ex.getClass());
      }
   }
}

L'output previsto sarà:

****** START *******
COSTRUISCO LA RISORSA
PrimaRisorsa: Faccio qualcosa
CHIUDO PrimaRisorsa
Eccezione nel try-with-resources:class java.io.IOException


In modo apparentemente strano ci rendiamo conto che viene catturata solo l'eccezione IOException generata dal metodo faiQualcosa(). E l'eccezione di chiusura automatica? In questo caso, cioè quando si verificano delle eccezioni sia nel blocco try-with-resources (sr.faiQualcosa()) sia durante la chiusura (sr.close()), la JVM sopprime l'eccezione generata nella chiusura automatica.

Che vuole dire sopprimere? Cosa significa che l'eccezione diventa Suppressed?
Spieghiamolo, come al solito, con un esempio.

Aggiungiamo nel catch un'istruzione (evidenziata in rosso):

package trywithresources;

public class TestSuppressedExceptions {
   public static void main(String[] args) {

      try (
         PrimaRisorsa sr = new PrimaRisorsa();
      ) {

         System.out.println("****** START *******");
         sr.faiQualcosa();

      } catch(Exception ex) {
         System.out.println("Eccezione nel try-with-resources:" + ex.getClass());
         ex.printStackTrace();
      }
   }
}

Oltre all'output precedente troviamo ora anche altre info:

****** START *******
COSTRUISCO LA RISORSA
PrimaRisorsa: Faccio qualcosa
CHIUDO PrimaRisorsa
Eccezione nel try-with-resources:class java.io.IOException
java.io.IOException: Eccezione di faiQualcosa generata da PrimaRisorsa
   at trywithresources.PrimaRisorsa.faiQualcosa(PrimaRisorsa.java:13)
   at trywithresources.TestSuppressedExceptions.main(TestSuppressedExceptions.java:14)
   Suppressed: java.lang.Exception: Eccezione di Chiusura generata da PrimaRisorsa
      at trywithresources.PrimaRisorsa.close(PrimaRisorsa.java:19)
      at trywithresources.TestSuppressedExceptions.main(TestSuppressedExceptions.java:16)

Come vedete oltre alla IOException vi è (in basso) la descrizione della Suppressed.

Qui entrano in gioco i nuovi metodi introdotti da Java 7 nella classe Throwable (la madre di tutte le Exceptions):

public final void addSuppressed(Throwable exception)
Aggiunge l'eccezione alle eccezioni soppresse.

public final Throwable[] getSuppressed()
Restituisce un array contenente tutte le eccezioni soppresse.

E il nuovo costruttore:
protected Throwable(String message, Throwable cause,
                       boolean enableSuppression, boolean writableStackTrace)


Guardiamo come recuperare una Suppressed Exception:

package trywithresources;

public class TestSuppressedExceptions {
   public static void main(String[] args) {

      System.out.println("****** START *******");
      try (
         PrimaRisorsa sr = new PrimaRisorsa();
      ) {

         sr.faiQualcosa();

      } catch(Exception ex) {
          System.out.println("Eccezione nel try-with-resources");
          int soppressa = ex.getSuppressed().length;
          for (int i=0; i<soppressa; i++)
              System.out.println("Eccezione Soppressa: " + ex.getSuppressed()[i]);
      }
   }
}


E nell'output, come previsto, troveremo l'eccezione generata dalla close():

****** START *******
COSTRUISCO LA RISORSA
PrimaRisorsa: Faccio qualcosa
CHIUDO PrimaRisorsa
Eccezione nel try-with-resources
Eccezione Soppressa: java.lang.Exception: Eccezione di Chiusura generata da PrimaRisorsa


Commenti

Post popolari in questo blog

Arrotondamento e troncamento in Java

Eclipse: Shortcuts (scorciatoie) da tastiera

Strutture dati: List, Set, Map

Creare un eseguibile Java