web-dev-qa-db-fra.com

jette Exception dans des blocs

Existe-t-il un moyen élégant de gérer les exceptions levées dans le bloc finally

Par exemple:

try {
  // Use the resource.
}
catch( Exception ex ) {
  // Problem with the resource.
}
finally {
   try{
     resource.close();
   }
   catch( Exception ex ) {
     // Could not close the resource?
   }
}

Comment éviter la try/catch dans le bloc finally?

96
Paul

Je le fais habituellement comme ça:

try {
  // Use the resource.
} catch( Exception ex ) {
  // Problem with the resource.
} finally {
  // Put away the resource.
  closeQuietly( resource );
}

Autre part:

protected void closeQuietly( Resource resource ) {
  try {
    if (resource != null) {
      resource.close();
    }
  } catch( Exception ex ) {
    log( "Exception during Resource.close()", ex );
  }
}
71
Darron

J'utilise généralement l'une des méthodes closeQuietly dans org.Apache.commons.io.IOUtils:

public static void closeQuietly(OutputStream output) {
    try {
        if (output != null) {
            output.close();
        }
    } catch (IOException ioe) {
        // ignore
    }
}
25
CJS

Si vous utilisez Java 7 et que resource implémente AutoClosable, vous pouvez le faire (en utilisant InputStream comme exemple):

try (InputStream resource = getInputStream()) {
  // Use the resource.
}
catch( Exception ex ) {
  // Problem with the resource.
}
22
Kevin Wong

Peut-être un peu exagéré, mais peut-être utile si vous laissez des exceptions bouillonner et que vous ne pouvez rien journaliser dans votre méthode (par exemple parce que c'est une bibliothèque et que vous préférez laisser le code appelant gérer les exceptions et la journalisation):

Resource resource = null;
boolean isSuccess = false;
try {
    resource = Resource.create();
    resource.use();
    // Following line will only run if nothing above threw an exception.
    isSuccess = true;
} finally {
    if (resource != null) {
        if (isSuccess) {
            // let close throw the exception so it isn't swallowed.
            resource.close();
        } else {
            try {
                resource.close();
            } catch (ResourceException ignore) {
                // Just swallow this one because you don't want it 
                // to replace the one that came first (thrown above).
            }
        }
    }
}

MISE À JOUR: J'ai examiné la question un peu plus et trouvé un bon post de blog écrit par quelqu'un qui y a clairement pensé plus que moi: http://illegalargumentexception.blogspot.com/2008/10/Java-how-not-to -make-mess-of-stream.html Il va encore plus loin et combine les deux exceptions en une, ce qui pourrait être utile dans certains cas.

8
MB.

Depuis Java 7, vous n'avez plus besoin de fermer explicitement les ressources d'un bloc finally. Vous pouvez également utiliser la syntaxe try -with-resources. L'instruction try-with-resources est une instruction try qui déclare une ou plusieurs ressources. Une ressource est un objet qui doit être fermé une fois que le programme est terminé. L'instruction try-with-resources garantit que chaque ressource est fermée à la fin de l'instruction. Tout objet implémentant Java.lang.AutoCloseable, qui inclut tous les objets implémentant Java.io.Closeable, peut être utilisé comme ressource.

Supposons le code suivant:

try( Connection con = null;
     Statement stmt = con.createStatement();
     Result rs= stmt.executeQuery(QUERY);)
{  
     count = rs.getInt(1);
}

Si une exception survient, la méthode close sera appelée sur chacune de ces trois ressources dans l'ordre inverse de leur création. Cela signifie que la méthode close serait d'abord appelée pour ResultSetm, puis l'instruction et à la fin pour l'objet Connection.

Il est également important de savoir que toutes les exceptions qui se produisent lorsque les méthodes de fermeture sont appelées automatiquement sont supprimées. Ces exceptions supprimées peuvent être récupérées par la méthode getsuppressed () définie dans la classe Throwable.

Source: https://docs.Oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

6
Soroosh

Ignorer les exceptions qui se produisent dans un bloc «finally» est généralement un problème. mauvaise idée à moins de savoir quelles seront ces exceptions et quelles conditions elles représenteront. Dans le modèle d'utilisation try/finally normal, le bloc try place les éléments dans un état auquel le code extérieur ne s'attendrait pas, et le bloc finally restaure l'état de ces éléments à ceux attendus par le code extérieur. Le code extérieur qui intercepte une exception s'attend généralement à ce que, malgré cette exception, tout ait été restauré dans un état normal. Par exemple, supposons qu'un code démarre une transaction et tente ensuite d'ajouter deux enregistrements; le bloc "finally" effectue une opération "annulation si non validée". Un appelant peut être préparé pour qu'une exception se produise lors de l'exécution de la deuxième opération "add" et peut s'attendre à ce que, s'il intercepte une telle exception, la base de données sera dans l'état où elle se trouvait avant la tentative de l'une ou l'autre opération. Toutefois, si une deuxième exception se produit lors de la restauration, des problèmes peuvent survenir si l'appelant émet des hypothèses sur l'état de la base de données. L'échec de la restauration représente un majeur crise - crise qui ne devrait pas être capturée par le code dans l'attente d'une simple exception "Impossible d'ajouter un enregistrement".

Mon penchant personnel serait de faire en sorte que les exceptions de méthode méthodes se produisent et de les envelopper dans une "exception CleanupFailedException", en reconnaissant qu'un tel échec représente un problème majeur et qu'une telle exception ne doit pas être prise à la légère.

3
supercat

Une solution, si les deux exceptions sont deux classes différentes

try {
    ...
    }
catch(package1.Exception err)
   {
    ...
   }
catch(package2.Exception err)
   {
   ...
   }
finally
  {
  }

Mais parfois, vous ne pouvez pas éviter ce deuxième essai. par exemple. pour fermer un flux

InputStream in=null;
try
 {
 in= new FileInputStream("File.txt");
 (..)// do something that might throw an exception during the analysis of the file, e.g. a SQL error
 }
catch(SQLException err)
 {
 //handle exception
 }
finally
 {
 //at the end, we close the file
 if(in!=null) try { in.close();} catch(IOException err) { /* ignore */ }
 }
2
Pierre

Après mûre réflexion, je trouve le code suivant le mieux:

MyResource resource = null;
try {
    resource = new MyResource();
    resource.doSomethingFancy();
    resource.close(); 
    resource = null;  
} finally {
    closeQuietly(resource)
}

void closeQuietly(MyResource a) {
    if (a!=null)
        try {
             a.close();
        } catch (Exception e) {
             //ignore
        }
}

Ce code garantit ce qui suit:

  1. La ressource est libérée à la fin du code
  2. Les exceptions levées lors de la fermeture de la ressource ne sont pas consommées sans traitement.
  3. Le code n'essaie pas de fermer la ressource deux fois, aucune exception inutile ne sera créée.
1
Grogi

Pourquoi voulez-vous éviter le blocage supplémentaire? Puisque le bloc finally contient des opérations "normales" qui peuvent générer une exception ET que vous voulez que le bloc finally soit exécuté complètement, vous DEVEZ intercepter des exceptions.

Si vous ne vous attendez pas à ce que le bloc finally génère une exception et que vous ne sachiez pas quand même gérer l'exception (vous ne feriez que vider la trace de la pile), laissez l'exception écumper la pile d'appels (supprimez le try-catch de bloc).

Si vous souhaitez réduire le nombre de saisies, vous pouvez implémenter un bloc externe global "try-catch", qui interceptera toutes les exceptions renvoyées dans des blocs:

try {
    try {
        ...
    } catch (Exception ex) {
        ...
    } finally {
        ...
    }

    try {
        ...
    } catch (Exception ex) {
        ...
    } finally {
        ...
    }

    try {
        ...
    } catch (Exception ex) {
        ...
    } finally {
        ...
    }
} catch (Exception ex) {
    ...
}
1
Eduard Wirch

Changer Resource de meilleure réponse en Closeable

Les flux implémentent Closeable Ainsi, vous pouvez réutiliser la méthode pour tous les flux

protected void closeQuietly(Closeable resource) {
    if (resource == null) 
        return;
    try {
        resource.close();
    } catch (IOException e) {
        //log the exception
    }
}
0
Ryan
try {
    final Resource resource = acquire();
    try {
        use(resource);
    } finally {
        resource.release();
    }
} catch (ResourceException exx) {
    ... sensible code ...
}

Travail accompli. Aucun test nul. Prise unique, y compris les exceptions d'acquisition et de libération. Bien sûr, vous pouvez utiliser l'idiome Execute Around et ne l'écrire qu'une fois pour chaque type de ressource.

0

Je fais habituellement ceci:

MyResource r = null;
try { 
   // use resource
} finally {   
    if( r != null ) try { 
        r.close(); 
    } catch( ThatSpecificExceptionOnClose teoc ){}
}

Raison: Si j'ai fini avec la ressource et que le seul problème que j'ai est de la fermer, je ne peux rien faire à ce sujet Cela n'a aucun sens non plus de tuer le fil entier si j'en ai fini avec la ressource de toute façon.

C'est l'un des cas où, du moins pour moi, il est prudent d'ignorer cette exception vérifiée.

À ce jour, je n'ai eu aucun problème à utiliser cet idiome. 

0
OscarRyz

Si vous le pouvez, vous devriez tester pour éviter la condition d'erreur.

try{...}
catch(NullArgumentException nae){...}
finally
{
  //or if resource had some useful function that tells you its open use that
  if (resource != null) 
  {
      resource.Close();
      resource = null;//just to be explicit about it was closed
  }
}

En outre, vous ne devriez probablement capturer que les exceptions sur lesquelles vous pouvez récupérer. Si vous ne pouvez pas récupérer, laissez-le se propager au niveau supérieur de votre programme. Si vous ne pouvez pas rechercher une condition d'erreur, vous devrez entourer votre code d'un bloc catch catch, comme vous l'avez déjà fait (bien que je vous recommande de détecter les erreurs spécifiques attendues).

0
Ken Henderson

Vous pouvez reformuler ceci dans une autre méthode ... 

public void RealDoSuff()
{
   try
   { DoStuff(); }
   catch
   { // resource.close failed or something really weird is going on 
     // like an OutOfMemoryException 
   }
}

private void DoStuff() 
{
  try 
  {}
  catch
  {
  }
  finally 
  {
    if (resource != null) 
    {
      resource.close(); 
    }
  }
}
0
Sam Saffron