web-dev-qa-db-fra.com

Fermeture Java InputStreams

J'ai des questions sur l'utilisation de la méthode close () lors de l'utilisation de Java InputStreams. D'après ce que je vois et lis de la plupart des développeurs, vous devriez toujours appeler explicitement close () sur un InputStream quand il n'est plus nécessaire. Mais aujourd'hui, je cherchais à utiliser un fichier de propriétés Java, et chaque exemple que j'ai trouvé a quelque chose comme ceci:

Properties props = new Properties();
try {
    props.load(new FileInputStream("message.properties"));
    //omitted.
} catch (Exception ex) {}

Avec l'exemple ci-dessus, il n'y a aucun moyen d'appeler explicitement close () car InputStream est inaccessible après son utilisation. J'ai vu de nombreuses utilisations similaires de InputStreams même si cela semble contredire ce que la plupart des gens disent à propos de la fermeture explicite. J'ai lu les JavaDocs d'Oracle et il ne mentionne pas si la méthode Properties.load () ferme le InputStream. Je me demande si cela est généralement acceptable ou s'il est préférable de faire quelque chose de plus comme ceci:

Properties props = new Properties();
InputStream fis = new FileInputStream("message.properties");
try {
    props.load(fis);
    //omitted.
} catch (Exception ex) {
    //omitted.
} finally {
    try {
        fis.close();
    } catch (IOException ioex) {
        //omitted.
    }
}

Quelle voie est meilleure et/ou plus efficace? Ou est-ce vraiment important?

62
Jason Watkins

Les exemples dans le Propriétés Tutorial fermez explicitement le FileInputStream après le chargement, donc je pense qu'il est sûr de supposer que la méthode load n'est pas responsable de cela, vous êtes .

// create and load default properties
Properties defaultProps = new Properties();
FileInputStream in = new FileInputStream("defaultProperties");
defaultProps.load(in);
in.close();

Juste pour référence, j'ai vérifié l'implémentation Apache Harmony de Propriétés , et elle ne ferme pas le flux en charge.

25
Bill the Lizard

La classe Properties encapsule le flux d'entrée dans un LineReader pour lire le fichier de propriétés. Puisque vous fournissez le flux d'entrée, il est de votre responsabilité de le fermer.

Le deuxième exemple est une meilleure façon de gérer le flux de loin, ne comptez pas sur quelqu'un d'autre pour le fermer pour vous.

Une amélioration que vous pourriez faire est d'utiliser IOUtils.closeQuietly ()

pour fermer le flux, par exemple:

Properties props = new Properties();
InputStream fis = new FileInputStream("message.properties");
try {
    props.load(fis);
    //omitted.
} catch (Exception ex) {
    //omitted.
} finally {
    IOUtils.closeQuietly(fis);
}
47
Jon

J'irais avec un essai avec des ressources (au moins pour Java 7+):

Properties props = new Properties();

try(InputStream fis = new FileInputStream("message.properties")) {
    props.load(fis);
    //omitted.
} catch (Exception ex) {
    //omitted.
}

L'appel close () doit être appelé automatiquement lorsque le bloc try est quitté.

30
Daniel Voina

Il ne mentionne pas dans la documentation que props.load fermerait le flux d'entrée. Vous devez fermer le flux d'entrée manuellement dans un bloc enfin comme vous le suggérez.

Il n'est pas normal qu'une fonction ferme un InputStream. La même convention s'applique que pour la mémoire dans les langues non récupérées: si possible, celui qui ouvre le flux doit le fermer. Sinon, il est très facile de laisser un flux ouvert (vous pensez qu'une fonction va le fermer, mais ce n'est pas le cas, ou quelque chose ...)

13
Adrian Smith

Si vous utilisez Java 7+, vous pouvez utiliser ceci:

try(InputStream is = new FileInputStream("message.properties")) {
    // ...
}
12
kwo2002

Il semble que le premier exemple de code finit par s'appuyer sur la méthode finalize dans FileInputStream pour réellement fermer le fichier. Je dirais que votre deuxième exemple est meilleur, même si dans les deux cas le dossier est fermé.

Il y a des cas comme les flux Byte où close ne fait rien et peut être omis, sinon je pense qu'il vaut mieux fermer explicitement le fichier dans un bloc finally. Si vous l'ouvrez, vous le fermez.

Il y a un livre sur le site d'Oracle appelé Java Platform Performance qui traite des finaliseurs dans son annexe, il dit:

Il est presque toujours préférable de faire votre propre nettoyage au lieu de compter sur un finaliseur. L'utilisation d'un finaliseur peut également laisser des ressources critiques qui ne seront pas récupérées pendant une durée indéterminée. Si vous envisagez d'utiliser un finaliseur pour vous assurer que les ressources importantes sont libérées en temps opportun, vous voudrez peut-être reconsidérer.

7
Nathan Hughes

Permettez-moi d'ajouter un petit quelque chose aux réponses des autres.

Si vous pouvez importer Apache Commons IO , vous pouvez utiliser les classes AutoCloseInputStream toujours très pratiques: vous encapsulez votre InputStream et ensuite vous utilisez simplement votre instance encapsulée et elle se ferme automatiquement dès que la fin de l'entrée est atteinte ou lorsque le flux est explicitement fermé, selon la première éventualité.

2
Unai Vivi