Ce qui arrive à un BufferedReader qui n'est pas fermé à l'intérieur d'un appelable.appel?
J'ai trois questions.
À expliquer, j'étais quelqu'un examen du code, et a remarqué BufferedReader
s parfois ne sont pas en cours de fermeture. Généralement, Eclipse donne un avertissement que c'est un risque de fuite de mémoire (et j'ai corrigé). Cependant, à l'intérieur d'un Callable intérieur de la classe, il n'y a pas d'avertissement.
class outerClass {
...
public void someMethod() {
Future<Integer> future = outputThreadPool.submit(new innerClass(this.myProcess.getInputStream(), threadName));
...
}
class innerClass implements Callable<Integer> {
private final InputStream stream;
private final String prepend;
innerClass(InputStream stream, String prepend) {
this.stream = stream;
this.prepend = prepend;
}
@Override
public Integer call() {
BufferedReader stdOut = new BufferedReader(new InputStreamReader(stream));
String output = null;
try {
while ((output = stdOut.readLine()) != null) {
log.info("[" + prepend + "] " + output);
}
} catch (IOException ignore) {
//I have no idea why we're ignoring this... :-|
}
return 0;
}
}
}
Les personnes qui ont écrit le code développeurs Java expérimentés, donc, ma première pensée est que c'est intentionnel... mais il pourrait être qu'ils étaient pressés quand ils ont écrit et il suffit de l'ignorer.
Mes questions sont:
-
Pourquoi n'Éclipse pas mis en évidence de ce (qui peut être répondu par la réponse aux questions suivantes)?
-
Quel est le pire qui pourrait arriver s'il est fermé à l'intérieur de la méthode call ()? (Je ne peux pas penser à une bonne raison... et j'ai cherché pendant un moment... mais peut-être que c'était voulu de ne pas fermer la BufferedReader)
-
Quel est le pire qui pourrait arriver si le BufferedReader est pas fermé à l'intérieur de la classe?
J'ai quelques réponses qui semblent contredire les uns les autres. D'une part, certaines personnes disent que le BufferedReader doit être fermé. D'autre part, ils disent qu'il ne devrait pas être fermée à cause de la fermeture de fermer la InputStream qu'il l'enveloppe, et l'appel de la classe pourraient en avoir besoin...
Voir cette question. Si une ressource comme une
InputStream
est passé dans une méthode, cela signifie que quelqu'un d'autre l'a ouvert, de sorte que quelqu'un d'autre doit la fermer. Si ils passent un flux de données de votre méthode, puis essayez de l'utiliser ailleurs par la suite, elle allait se briser, car il serait fermé (fermeture d'un BufferReader
ferme ses cours d'eau), même si votre méthode peut uniquement avoir besoin de faire une chose avec le cours d'eau.Jetez un oeil à mes modifications à ma réponse.
OriginalL'auteur GLaDOS | 2012-08-30
Vous devez vous connecter pour publier un commentaire.
Je dirais que depuis qu'ils sont la création d'un
BufferedReader
autour d'un mêmeInputStream
, le code est sûr de ne pas appelerclose()
. Le code qui appelleclose()
devrait toujours être le code qui crée le flux et le fait à l'aide de try/finally.Une autre remarque: le code semble être sortie d'enregistrement à partir d'un autre processus. Vous n'auriez probablement pas être en mesure de fermer le flux de données, de toute façon. Sans le tester moi-même, je ne suis pas sûr de ce qui se passerait si vous avez fermé un flux à partir d'un autre processus.
Oh, et le
IOException
n'est pas susceptible de se produire parce que le flux est à venir à partir d'un autre processus. C'est pas susceptible de se produire à moins que certains d'erreur irrécupérable se produit. Ce ne serait pas encore une mauvaise idée pour vous connecter à l'exception d'une certaine manière, cependant.Modifier à l'adresse de votre commentaire au sujet des réponses mitigées:
Nous allons utiliser un flux de sortie et
BufferedWriter
comme un exemple de ce temps:Cela fonctionne. La méthode writeLine est utilisé en tant que délégué à la création de
writer
et en train d'écrire une seuleline
pour le fichier. Bien sûr, cette logique pourrait être quelque chose de plus complexe, telle que la transformation d'un objet dans unString
et de l'écriture. Cela rend lemain
méthode un peu plus facile à lire.Maintenant, si au lieu de cela, nous avons fermé la BufferedWriter?
Essayer de l'exécuter, et il échouera à chaque fois sur la deuxième
writeLine
appel. C'est une bonne pratique de toujours à proximité des cours d'eau où ils sont créés, au lieu d'où ils sont passés. Il peut être bien au début, mais ensuite, essayer de modifier le code plus tard, pourrait provoquer des erreurs. Si j'ai commencé avec seulement 1writeLine
appel avec la mauvaise méthode et quelqu'un d'autre veut ajouter une seconde, ils auraient à refactoriser le code de sorte quewriteLine
ne pas fermer le flux de données, de toute façon. Approchez-heureux peut causer des maux de tête en bas de la route.Noter également que, techniquement, la
BufferedWriter
n'est pas la réelle gérer vos ressources système, l'FileOutputStream
est, de sorte que vous devriez être à la clôture, le véritable ressource de toute façon.Donc, la règle de base: seules près de votre cours d'eau où vous les créez, et toujours faire de la création et de clôture dans un try/finally bloc (ou Java 7 est génial essayez de ressources de bloc, qui ne la clôture pour vous).
Également droit sur la connexion de sortie d'un autre processus. Ce processus était en train de faire un travail sur le fichier transmis par le flux en question, et il est important de suivre les éventuelles erreurs ou des problèmes dans les journaux.
Aussi génial et merci pour la réponse plus détaillée. Vous avez été plus d'aide que mon dev manager qui était de superviser le code en question au moment de l'écriture 🙂
Vous êtes les bienvenus 🙂 Content d'avoir pu aider.
OriginalL'auteur Brian
BuffereddReader fermer()
Donc, si vous ne fermez pas(), système des ressources peut être toujours associée avec le lecteur qui peut causer une fuite de mémoire.
Pourquoi eclipse ne pas mettre en valeur: il n'est pas d'erreur de compilation si vous ignorez l'appel à close(), de sorte que l'éclipse ne mettent pas en évidence.
Oui, seulement BufferedReader objet peut être GCed, mais d'autres Socket choses, je ne pense pas que GC ne fait rien pour cela.
Mais eclipse t mettez-le en surbrillance lorsqu'elle n'est pas dans un intérieur de classe... c'est ce Qui est déroutant pour moi.
OriginalL'auteur kosa
Vous ne voulez pas fermer la
BufferedReader
dans ce cas. LeInputStream
qui a été adoptée pour le constructeur est l'objet qui peut être associé à un système de ressources. LeBufferedReader
et laInputStreamReader
sont juste des wrappers autour de cela. La fermeture de laBufferedReader
serait aussi fermer laInputStream
, qui peut ne pas être ce que l'appelant voulait.OriginalL'auteur Kenster
Ne met pas en évidence et il est vrai, comme un flux de données peut être fermé à un autre endroit de l'appel de méthode.
S'il est fermé à l'intérieur de l'appel de méthode que d'autres threads peuvent l'utiliser pour le moment.
Avec le
BufferdRreader
rien, mais si vous perdez la référence de flux et ne peut pas la fermer et cela conduit à une fuite de mémoire.OriginalL'auteur Roman C
N'importe où vous ouvrez le flux, vous devriez la fermer dans le bloc finally et c'est une bonne pratique pour tester le flux de
null
ainsi, parce que si le fichier n'est pas en vigueur le flux seranull
, une exception sera levée (FileNotFoundException
) mais enfin bock est fait. I. e. le contenu de l'appel de la méthode doit être:Ou si vous êtes autorisé à utiliser Java 7, vous pouvez utiliser les avantages de
AutoCloseable
de l'interface et la nouvelle structure de la langue à cette fin.voir http://www.oracle.com/technetwork/articles/java/trywithresources-401775.html
Oh, vous avez raison. J'ai modifié légèrement. Maintenant, il est correct.
Assez sûr que nous n'allons pas à 7 de si tôt 🙁
OriginalL'auteur Jiri Kremser