19 votes

Comment gérer correctement une IOException de close() ?

Les classes d'E/S Java java.io.Reader , java.io.Writer , java.io.InputStream , java.io.OutpuStream et leurs diverses sous-classes ont toutes une close() qui peut lancer un IOException .

Existe-t-il un consensus sur la manière appropriée de traiter ces exceptions ?

J'ai souvent vu des recommandations pour les ignorer silencieusement, mais cela ne semble pas correct, et au moins dans le cas de ressources ouvertes à l'écriture, un problème lors de la fermeture du fichier pourrait signifier que les données non vidées ne pourraient pas être écrites/envoyées.

D'autre part, lorsque je lis des ressources, je ne comprends pas du tout pourquoi close() pourrait lancer et ce qu'il faut faire.

Existe-t-il donc une recommandation standard ?

Une question connexe est Est-ce que close ne lève jamais une IOException ? mais il s'agit plutôt de savoir quelles sont les implémentations réellement faire et non sur la façon de gérer les exceptions.

0voto

dogbane Points 85749

Cela dépend de ce que vous fermez. Par exemple, la fermeture d'un StringWriter ne fait rien. Les javadocs sont claires à ce sujet. Dans ce cas, vous pouvez ignorer l'exception IOException car vous savez qu'elle ne sera jamais générée. Techniquement, vous n'avez même pas besoin d'appeler close .

/**
 * Closing a <tt>StringWriter</tt> has no effect. The methods in this
 * class can be called after the stream has been closed without generating
 * an <tt>IOException</tt>.
 */
public void close() throws IOException {
}

Pour les autres flux, enregistrez et traitez l'exception comme il se doit.

0voto

En général, la gestion des ressources devrait ressembler à ceci :

final Resource resource = context.acquire();
try {
    use(resource);
} finally {
    resource.release();
}

Dans le cas (improbable) de release en lançant une exception, toute exception lancée par use seront abandonnés. Je n'ai pas de problème à ce que l'exception lancée la plus proche du receveur gagne. Je crois que les blocs ARM dans le JDK7( ?) feront quelque chose de fou dans ce cas, comme relancer l'exception de type use exception avec le release exception jointe.

Si vous utilisez l'idiome "Execute Around", vous pouvez regrouper ces décisions et le code potentiellement désordonné à un (ou quelques) endroit(s).

0voto

rodion Points 6275

Ignorer ou se contenter de fermer les yeux est généralement une mauvaise idée. Même s'il est vrai que vous ne pouvez pas vous en remettre, les exceptions d'E/S doivent toujours être traitées de manière unifiée afin de garantir que votre logiciel se comporte de manière unifiée.

Je suggérerais au moins de procéder comme suit :

//store the first exception caught
IOException ioe = null;
Closeable resource = null;
try{
  resource = initializeResource();
  //perform I/O on resource here
}catch(IOException e){
  ioe = e;
}finally{
  if (resource != null){
    try{
      resource.close();
    }catch(IOException e){
      if(null == ioe){
        //this is the first exception
        ioe = e;
      }else{
        //There was already another exception, just log this one.
        log("There was another IOException during close. Details: ", e);
      }
    }
  }
}

if(null != ioe){
  //re-throw the exception to the caller
  throw ioe;
}

Ce qui précède est assez verbeux mais fonctionne bien, car il préfèrera le fichier IOException pendant les E/S sur la ressource à celle pendant la fermeture, car elle est plus susceptible de contenir des informations intéressantes pour le développeur. Le code lancera également un IOException lorsque quelque chose ne va pas, afin d'obtenir un comportement unifié.

Il y a peut-être des façons plus agréables de le faire, mais vous voyez l'idée.

L'idéal serait de créer un nouveau type d'exception qui permettrait de stocker des exceptions similaires, de sorte qu'au cas où vous auriez deux IOException vous pourriez les stocker tous les deux.

-2voto

Ehtesh Choudhury Points 1395

Dans la plupart des cas, close() ne lève pas vraiment une IOException. Voici le code pour InputStream.java :

  public void close() throws IOException
  {
    // Do nothing
  }

Les erreurs liées à la fermeture d'une ressource réseau doivent vraiment être de type RuntimeException Vous pouvez en effet déconnecter une ressource en réseau après que le programme s'y soit connecté.

Vous pouvez voir quelques exemples de diverses mises en œuvre de l'option Lecteur /Writer et Streams en utilisant Google Code Search. Ni BufferedReader ni PipedReader ne lèvent une IOException, donc je pense que vous êtes en sécurité en ne vous en souciant pas. Si vous êtes vraiment inquiet, vous pouvez vérifier l'implémentation des bibliothèques que vous utilisez pour voir si vous avez besoin de vous soucier de cette exception.

Comme d'autres l'ont mentionné, vous ne pouvez pas faire grand-chose à propos de l'exception IOException à part l'enregistrer.

Après tout, try/catch blocks dans le finally Les clauses sont plutôt moches.

Edit :

Une inspection plus poussée révèle des sous-classes de IOException comme InterruptedIOException , SyncFailedException y ObjectStreamException ainsi que les classes qui en héritent. Ainsi, le fait d'attraper un IOException serait trop générale - vous ne sauriez pas quoi faire avec l'information, à part l'enregistrer, car elle pourrait provenir de toute une série d'erreurs.

Edit 2 :

Urk, BufferedReader était un mauvais exemple, puisqu'il prend un Reader comme entrée. Je l'ai changé en InputStream.java

Cependant, il y a une hiérarchie avec InputStream <= FilterInputStream <= BufferedInputStream <= InputStreamReader (via l'héritage et les instances privées) qui remontent tous jusqu'au close() méthode dans InputStream .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X