Question

Existe-t-il un moyen élégant de gérer les exceptions lancées dans un 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 le try / catch dans le bloc <=>?

Était-ce utile?

La solution

Je le fais habituellement comme ça:

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

Ailleurs:

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

Autres conseils

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

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

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.
}

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, c'est une bibliothèque et vous préféreriez laisser le code appelant gérer les exceptions et enregistrement):

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é une bonne publication sur un blog de quelqu'un qui a clairement pensé à cette question plus que moi: http://illegalargumentexception.blogspot.com/2008/10/java-how-not-tmemake-mess-of -stream.html Il va encore plus loin et combine les deux exceptions en une, ce qui pourrait être utile dans certains cas.

À partir de Java 7, vous n'avez plus besoin de fermer explicitement les ressources d'un bloc finally , mais vous pouvez utiliser la syntaxe essayer -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 se produit, la méthode fermer 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

Ignorer les exceptions qui se produisent dans un bloc "finally" est généralement une mauvaise idée à moins de savoir quelles seront ces exceptions et quelles conditions elles représenteront. Dans le modèle d'utilisation normal try/finally, 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 correspondant aux attentes du 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 " enfin " block effectue une " restauration si non engagé " opération. Un appelant peut être préparé pour qu'une exception se produise lors de l'exécution de la deuxième & "Add &"; opération, et peut s’attendre à ce que s’il intercepte une telle exception, la base de données sera dans l’état qu’elle était avant la tentative de l’opération. Si, toutefois, 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 une crise majeure - une crise qui ne devrait pas être capturée par le code dans l'attente d'un simple & Quot; Échec lors de l'ajout d'un enregistrement & Quot; exception.

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

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 */ }
 }

Pourquoi voulez-vous éviter le blocage supplémentaire? Puisque le bloc finally contient & "Normal &"; les opérations qui peuvent générer une exception ET vous voulez que le bloc finally s'exécute complètement, vous DEVEZ intercepter des exceptions.

Si vous ne vous attendez pas à ce que le bloc finally émette une exception et que vous ne sachiez pas gérer l’exception de toute façon (il vous suffirait de vider la trace de la pile), laissez l’exception bouillonner la pile d’appels (supprimez le contrôle du bloc finally).

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

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

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

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

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 généré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.

Si vous le pouvez, vous devriez effectuer un test 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
  }
}

De plus, vous ne devriez probablement capturer que les exceptions sur lesquelles vous pouvez effectuer la récupération. Si vous ne pouvez pas récupérer, laissez-le se propager au niveau supérieur de votre programme. Si vous ne parvenez 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 recommande de détecter les erreurs spécifiques attendues).

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

Je fais habituellement ceci:

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

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

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.

try {
    final Resource resource = acquire();
    try {
        use(resource);
    } finally {
        resource.release();
    }
} catch (ResourceException exx) {
    ... sensible code ...
}

Travail terminé. 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.

Remplacer Resource de meilleure réponse par Closeable

Streams implémente <=> Vous pouvez ainsi 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
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top