Question

    

Cette question a déjà une réponse ici:

         

Remarque: Cette question et la plupart de ses réponses Jusqu'à la date avant la sortie de Java 7. Java 7 fournit la fonctionnalité de gestion automatique des ressources pour ce faire easilly. Si vous utilisez Java 7 ou version ultérieure, vous devez passer à href="https://stackoverflow.com/a/21723193"> .


Ce qui est considéré comme le meilleur et le plus complet de fermer les flux imbriqués en Java? Par exemple, considérez la configuration:

FileOutputStream fos = new FileOutputStream(...)
BufferedOS bos = new BufferedOS(fos);
ObjectOutputStream oos = new ObjectOutputStream(bos);

Je comprends le besoin étroite d'être assuré (probablement en utilisant une clause finally). Ce que je me demande au sujet est, est-il nécessaire de faire explicitement que les flux imbriqués sont fermés, ou est-ce suffisant pour il suffit de fermer le flux externe (OOS)?

Une chose que je remarque, au moins traiter cet exemple spécifique, est que les flux internes ne semblent jeter FileNotFoundExceptions. Ce qui semble impliquer qu'il n'y a pas techniquement besoin de se soucier de les fermer si elles échouent.

Voici ce qu'un collègue a écrit:


Techniquement, si elle était mise en œuvre à droite, la fermeture de la plus à l'extérieur flux (OOS) devrait être suffisant. Mais la mise en œuvre semble erronée.

Exemple: BufferedOutputStream hérite close () à partir de FilterOutputStream, qu'il définit comme:

 155       public void close() throws IOException {
 156           try {
 157             flush();
 158           } catch (IOException ignored) {
 159           }
 160           out.close();
 161       }

Toutefois, si flush () lance une exception d'exécution pour une raison quelconque, out.close () ne sera jamais appelé. Il semble donc « plus sûr » (mais laid) à vous inquiétez surtout de fermeture FOS, qui maintient le fichier ouvert.


Ce qui est considéré comme les mains vers le bas le mieux, quand-vous-absolument besoin à être-sûr, l'approche de la fermeture de flux imbriqués?

et quels sont les Java officielles Sun / docs qui traitent en détail bien?

Était-ce utile?

La solution

Je fais habituellement ce qui suit. Tout d'abord, définir une classe basée sur un modèle méthode pour traiter le try / catch gâchis

import java.io.Closeable;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

public abstract class AutoFileCloser {
    // the core action code that the implementer wants to run
    protected abstract void doWork() throws Throwable;

    // track a list of closeable thingies to close when finished
    private List<Closeable> closeables_ = new LinkedList<Closeable>();

    // give the implementer a way to track things to close
    // assumes this is called in order for nested closeables,
    // inner-most to outer-most
    protected final <T extends Closeable> T autoClose(T closeable) {
            closeables_.add(0, closeable);
            return closeable;
    }

    public AutoFileCloser() {
        // a variable to track a "meaningful" exception, in case
        // a close() throws an exception
        Throwable pending = null;

        try {
            doWork(); // do the real work

        } catch (Throwable throwable) {
            pending = throwable;

        } finally {
            // close the watched streams
            for (Closeable closeable : closeables_) {
                if (closeable != null) {
                    try {
                        closeable.close();
                    } catch (Throwable throwable) {
                        if (pending == null) {
                            pending = throwable;
                        }
                    }
                }
            }

            // if we had a pending exception, rethrow it
            // this is necessary b/c the close can throw an
            // exception, which would remove the pending
            // status of any exception thrown in the try block
            if (pending != null) {
                if (pending instanceof RuntimeException) {
                    throw (RuntimeException) pending;
                } else {
                    throw new RuntimeException(pending);
                }
            }
        }
    }
}

Notez le « en attente » exception -. Cela prend en charge le cas où une exception levée pendant près masquerait une exception, nous pourrions vraiment se soucier de

La tente finalement de fermer de l'extérieur de tout premier flux décoré, donc si vous aviez un BufferedWriter enroulant un FileWriter, nous essayons de fermer la BuffereredWriter d'abord, et si cela échoue, essayez toujours de fermer le FileWriter lui-même. (Notez que la définition de Closeable appelle close () pour ignorer l'appel si le flux est déjà fermé)

Vous pouvez utiliser la classe ci-dessus comme suit:

try {
    // ...

    new AutoFileCloser() {
        @Override protected void doWork() throws Throwable {
            // declare variables for the readers and "watch" them
            FileReader fileReader = 
                    autoClose(fileReader = new FileReader("somefile"));
            BufferedReader bufferedReader = 
                    autoClose(bufferedReader = new BufferedReader(fileReader));

            // ... do something with bufferedReader

            // if you need more than one reader or writer
            FileWriter fileWriter = 
                    autoClose(fileWriter = new FileWriter("someOtherFile"));
            BufferedWriter bufferedWriter = 
                    autoClose(bufferedWriter = new BufferedWriter(fileWriter));

            // ... do something with bufferedWriter
        }
    };

    // .. other logic, maybe more AutoFileClosers

} catch (RuntimeException e) {
    // report or log the exception
}

En utilisant cette approche, vous ne devez jamais vous soucier de la try / catch / finally pour traiter les dossiers de fermer à nouveau.

Si cela est trop lourd pour votre usage, au moins penser à la suite de la try / catch et « en attente » approche variable, il utilise.

Autres conseils

Lors de la fermeture des flux enchaînées, il vous suffit de fermer le flux externe. Toute erreur se propageront la chaîne et être pris.

Reportez-vous à Java flux E / S pour plus de détails.

Pour répondre à la question

  

Toutefois, si flush () lance une exception d'exécution pour une raison quelconque, out.close () ne sera jamais appelé.

Ce n'est pas juste. Une fois que vous attrapez et ignorer cette exception, l'exécution reprendra après le retour bloc catch et l'instruction out.close() sera exécutée.

Votre collègue fait un bon point sur le Runtime Exception. Si vous avez besoin absolument le flux à être fermé, vous pouvez toujours essayer de fermer chacun individuellement, de l'extérieur, s'arrêtant à la première exception.

Dans l'ère Java 7, try-with-ressources est certainement le moyen aller. Comme mentionné dans plusieurs réponses précédentes, la demande de fermeture se propage à partir du courant la plus extérieure dans le courant le plus interne. Ainsi, un seul proche est tout ce qui est nécessaire.

try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f))) {
  // do something with ois
}

Il y a cependant un problème avec ce modèle. L'essai avec-ressources ne sont pas au courant de la FileInputStream intérieure, donc si le constructeur ObjectInputStream lance une exception, FileInputStream est jamais fermé (jusqu'à ce que le garbage collector arrive à lui). La solution est ...

try (FileInputStream fis = new FileInputStream(f); ObjectInputStream ois = new ObjectInputStream(fis)) {
  // do something with ois
}

Ce n'est pas aussi élégant, mais est plus robuste. Que ce soit en réalité un problème dépendra de quelles exceptions peuvent être levées pendant la construction de l'objet externe (s). ObjectInputStream peut jeter IOException qui pourrait bien se traité par une application sans terminer. De nombreuses classes de cours d'eau ne jettent exceptions non vérifiées, ce qui pourrait bien entraîner la résiliation de l'application.

Il est une bonne pratique d'utiliser Apache Commons pour gérer IO objets liés.

Dans la clause finally utilisation IOUtils

IOUtils.closeQuietly (bWriter); IOUtils.closeQuietly (oWritter);

Extrait de code ci-dessous.

BufferedWriter bWriter = null;
OutputStreamWriter oWritter = null;

try {
  oWritter  = new OutputStreamWriter( httpConnection.getOutputStream(), "utf-8" );
  bWriter = new BufferedWriter( oWritter );
  bWriter.write( xml );
}
finally {
  IOUtils.closeQuietly(bWriter);
  IOUtils.closeQuietly(oWritter);
}

Le collègue soulève un point intéressant, et il y a lieu de discuter de toute façon.

Personnellement, j'ignorer la RuntimeException, car une exception non contrôlée signifie un bogue dans le programme. Si le programme est incorrect, le corriger. Vous ne pouvez pas « gérer » un mauvais programme lors de l'exécution.

Ceci est une question étonnamment maladroite. (Même en supposant que le code acquire; try { use; } finally { release; } est correct.)

Si la construction du décorateur échoue, vous ne serez pas fermer le flux sous-jacent. Par conséquent, vous avez besoin de fermer le flux sous-jacent explicitement, que ce soit dans l'utilisation ou enfin, après plus diifcult après avoir remis avec succès sur la ressource au décorateur).

Si une exception provoque l'exécution à l'échec, voulez-vous vraiment désintoxiquer?

Certains décorateurs ont en fait des ressources elles-mêmes. Le courant de la mise en œuvre Sun ZipInputStream par exemple dispose d'une mémoire de tas non-Java attribué.

Il a été affirmé que (IIRC) les deux tiers des ressources utilise dans la bibliothèque Java sont mises en œuvre de manière manifestement erronée.

Alors que BufferedOutputStream ferme même sur un IOException de flush, BufferedWriter ferme correctement.

Mon conseil: Fermer les ressources aussi directement que possible et ne les laissez pas entacher autre code. OTOH, vous pouvez passer trop de temps sur cette question - si OutOfMemoryError est jeté il est agréable de se comporter bien, mais d'autres aspects de votre programme sont probablement une plus grande priorité et le code de la bibliothèque est probablement cassé dans cette situation de toute façon. Mais je toujours écrire:

final FileOutputStream rawOut = new FileOutputStream(file);
try {
    OutputStream out = new BufferedOutputStream(rawOut);
    ... write stuff out ...
    out.flush();
} finally {
    rawOut.close();
}

(Look: Aucune prise)

Et peut-être utiliser le langage autour Exécuter.

Le Java SE 7 essayer avec-ressources doesn « t semblent être mentionnés. Il élimine besoin de faire explicitement une Refermer tout à fait, et je aime bien l'idée.

Malheureusement, pour le développement Android ce que doux devient disponible en utilisant Android Studio (je pense) et ciblage KitKat et au-dessus .

Aussi, vous ne devez pas fermer tous les flux imbriqués

vérifier http://ckarthik17.blogspot.com/2011/02/closing-nested -streams.html

J'utilise pour fermer les flux comme celui-ci, sans try-catch dans la nidification enfin blocs

public class StreamTest {

public static void main(String[] args) {

    FileOutputStream fos = null;
    BufferedOutputStream bos = null;
    ObjectOutputStream oos = null;

    try {
        fos = new FileOutputStream(new File("..."));
        bos = new BufferedOutputStream(fos);
        oos = new ObjectOutputStream(bos);
    }
    catch (Exception e) {
    }
    finally {
        Stream.close(oos,bos,fos);
    }
  }   
}

class Stream {

public static void close(AutoCloseable... array) {
    for (AutoCloseable c : array) {
        try {c.close();}
        catch (IOException e) {}
        catch (Exception e) {}
    }
  } 
}

Les JavaDocs de Sun sont RuntimeExceptions dans leur documentation, comme le montre de InputStream procédé de lecture (byte [], int, int) ; documenté comme jetant NullPointerException et IndexOutOfBoundsException.

Les href="http://java.sun.com/javase/6/docs/api/java/io/FilterOutputStream.html#flush()" de () que la documentation de lancer IOException, donc il ne fait pas jeter des RuntimeExceptions. Tout qui pourrait être jeté serait très probablement enveloppé dans un IIOException.

Il pourrait encore jeter un Error , mais il y a vous ne pouvez pas faire beaucoup de ceux; Sun vous recommande de ne pas essayer de les attraper.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top