eclipse 在 callable.call 中没有关闭的 BufferedReader 会发生什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12203291/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What happens to a BufferedReader that doesn't get closed within a callable.call?
提问by GLaDOS
I have three questions.
我有三个问题。
To explain, I was reviewing someone's code, and noticed BufferedReader
s sometimes aren't being closed. Usually, Eclipse gives a warning that this is a potential memory leak (and I fix it). However, within a Callable inner class, there is no warning.
解释一下,我正在某人的代码,并注意到BufferedReader
s 有时没有被关闭。通常,Eclipse 会发出警告,指出这是潜在的内存泄漏(我已修复它)。但是,在 Callable 内部类中,没有警告。
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;
}
}
}
The people who wrote the code are experienced Java developers, so my first thought is that it's intentional... but it could be they were in a hurry when they wrote it and just overlooked it.
编写代码的人都是有经验的 Java 开发人员,所以我的第一个想法是这是故意的……但也可能是他们编写代码时匆忙而忽略了它。
My questions are:
我的问题是:
Why does Eclipse not highlight this (which may be answered by the answer to the following questions)?
What is the worst that could happen if it's closed within the call() method? (I can't think of a good reason... and I've been searching for a while... but maybe it was intentional not to close the BufferedReader)
What is the worst that could happen if the BufferedReader is notclosed within the inner class?
为什么 Eclipse 没有突出显示这一点(可以通过以下问题的答案来回答)?
如果它在 call() 方法中关闭,可能发生的最坏情况是什么?(我想不出一个很好的理由......我已经搜索了一段时间......但也许是故意不关闭 BufferedReader)
如果 BufferedReader没有在内部类中关闭,最糟糕的情况是什么?
采纳答案by Brian
I would say that since they're creating a BufferedReader
around a given InputStream
, the code is safe not calling close()
. The code that calls close()
should always be the code that creates the stream and done using try/finally.
我会说,因为他们BufferedReader
围绕给定InputStream
的close()
. 调用的代码close()
应该始终是创建流并使用 try/finally 完成的代码。
public static void read(String str) throws IOException {
FileInputStream stream = null
try {
stream = new FileInputStream(str);
readStreamToConsole(stream);
} finally {
if (stream != null)
stream.close();
}
}
private static void readStreamToConsole(InputStream stream) {
BufferedReader stdOut = new BufferedReader(new InputStreamReader(stream));
String output = null;
while ((output = stdOut.readLine()) != null)
System.out.println(output);
}
Another note: your code appears to be logging output from some other process. You probably wouldn't be able to close the stream anyway. Without testing it myself, I'm not sure what would happen if you closed a stream from another process.
另一个注意事项:您的代码似乎正在记录来自其他某个进程的输出。无论如何,您可能无法关闭流。如果没有自己测试,我不确定如果您关闭来自另一个进程的流会发生什么。
Oh, and the IOException
isn't likely to happen because the stream is coming from another process. That's not likely to happen unless some irrecoverable error occurs. It still wouldn't be a bad idea to log the exception somehow, though.
哦,这IOException
不太可能发生,因为流来自另一个进程。除非发生一些不可恢复的错误,否则这不太可能发生。不过,以某种方式记录异常仍然不是一个坏主意。
Edit to address your comment about mixed answers:
编辑以解决您对混合答案的评论:
Let's use an output stream and BufferedWriter
as an example this time:
让我们使用输出流BufferedWriter
作为例子:
private static final String NEWLINE = System.getProperty("line.separator");
public static void main(String[] args) throws IOException {
String file = "foo/bar.txt";
FileOutputStream stream = null;
try {
stream = new FileOutputStream(file);
writeLine(stream, "Line 1");
writeLine(stream, "Line 2");
} finally {
if (stream != null)
stream.close();
}
}
private static void writeLine(OutputStream stream, String line) throws IOException {
BufferedWriter writer = new BufferedWriter(new InputStreamWriter(stream));
writer.write(line + NEWLINE);
}
This works. The writeLine method is used as a delegate to creating writer
and actually writing a single line
to the file. Of course, this logic could be something more complex, such as turning an object into a String
and writing it. This makes the main
method a little easier to read too.
这有效。writeLine 方法用作创建writer
单个line
文件并将其实际写入文件的委托。当然,这个逻辑可以更复杂一些,比如把一个对象变成 aString
并写出来。这也使该main
方法更易于阅读。
Now, what if instead, we closed the BufferedWriter?
现在,如果我们关闭 BufferedWriter 呢?
private static void writeLine(OutputStream stream, String line) throws IOException {
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new InputStreamWriter(stream));
writer.write(line + NEWLINE);
} finally {
if (writer != null)
writer.close();
}
}
Try running it with that, and it will fail every time on the second writeLine
call. It's good practice to always close streams where they're created, instead of where they're passed. It may be fine initially, but then trying to change that code later could result in errors. If I started with only 1 writeLine
call with the bad method and someone else wanted to add a second one, they'd have to refactor the code so that writeLine
didn't close the stream anyway. Getting close-happy can cause headaches down the road.
尝试运行它,它会在第二次writeLine
调用时失败。总是在创建流的地方而不是通过它们的地方关闭流是一种很好的做法。最初可能没问题,但稍后尝试更改该代码可能会导致错误。如果我开始时只writeLine
调用了1 次错误方法,而其他人想添加第二次调用,则他们必须重构代码,以便writeLine
无论如何都不会关闭流。获得亲密的快乐可能会导致头痛。
Also note that technically, the BufferedWriter
isn't the actual handle to your system resource, the FileOutputStream
is, so you should be closing on the actual resource anyway.
另请注意,从技术上讲,这BufferedWriter
不是系统资源的实际句柄,FileOutputStream
而是,因此无论如何您都应该关闭实际资源。
So, rule of thumb: only close your streams where you create them, and always do the creation and closing in a try/finally block (or Java 7's awesome try/resource block, which does the closing for you).
所以,经验法则:只在你创建它们的地方关闭你的流,并且总是在 try/finally 块(或 Java 7 的很棒的try/resource 块,它为你关闭)中进行创建和关闭。
回答by Kenster
You may not want to close the BufferedReader
in this case. The InputStream
which was passed to the constructor is the object that may be associated with a system resource. The BufferedReader
and the InputStreamReader
are just wrappers around that. Closing the BufferedReader
would also close the InputStream
, which may not be what the caller wanted.
BufferedReader
在这种情况下,您可能不想关闭。在InputStream
将其传递给构造是可与系统资源相关联的对象。TheBufferedReader
和 theInputStreamReader
只是围绕它的包装。关闭BufferedReader
也会关闭InputStream
,这可能不是调用者想要的。
回答by Roman C
Doesn't highlight and it's true, because a stream can be closed somewhere else out of the call method.
If it's closed within the call method that other threads may be using it at the moment.
With the
BufferdRreader
nothing but if you loose the reference to stream and cannot close it and this leads to a memory leak.
没有突出显示,这是真的,因为流可以在调用方法之外的其他地方关闭。
如果它在 call 方法中关闭,则其他线程目前可能正在使用它。
随着
BufferdRreader
不过,如果你松流的参考,不能关闭它,这会导致内存泄漏。
回答by Jiri Kremser
No matter where you open the stream you should close it in the finally block and it is a good practice to test the stream for null
as well, because if the file is not existing the stream will be null
, exception will be thrown (FileNotFoundException
) but the finally bock is done. I.e. the content of the call method should be:
无论您在哪里打开流,您都应该在 finally 块中关闭它,并且测试流也是一个好习惯null
,因为如果文件不存在,流将是null
,异常将被抛出 ( FileNotFoundException
) 但 finally博克完成。即调用方法的内容应该是:
BufferedReader stdOut = null;
String output = null;
try {
stdOut = new BufferedReader(new InputStreamReader(stream));
while ((output = stdOut.readLine()) != null) {
log.info("[" + prepend + "] " + output);
}
} catch (FileNotFoundException ex) {
log.warn("Unable to open nonexisten file " + whichOne);
} catch (IOException ex) {
log.warn("Unable to read from stream");
} finally {
if (stdOut != null) {
try {
stdOut.close();
} catch (IOException e) {
log.warn("Unable to close the stream");
}
}
}
return 0;
Or if you are allowed to use Java 7 you can use the benefits of AutoCloseable
interface and the new language structure for this purpose.
see http://www.oracle.com/technetwork/articles/java/trywithresources-401775.html
或者,如果您被允许使用 Java 7,您可以AutoCloseable
为此目的使用界面和新语言结构的好处。见http://www.oracle.com/technetwork/articles/java/trywithresources-401775.html
回答by kosa
BuffereddReader close()
BuffereddReader关闭()
Closes this stream and releases any system resources associated with it. If the stream is already closed then invoking this method has no effect.
关闭此流并释放与其关联的所有系统资源。如果流已经关闭,则调用此方法无效。
So, if you don't close(), system resources may be still associated with the reader which may cause memory leak.
因此,如果您不关闭(),系统资源可能仍然与阅读器相关联,这可能会导致内存泄漏。
Why eclipse not highlighting: it is not compile time error if you ignore calling close(), so eclipse don't highlight.
为什么 eclipse 不突出显示:如果忽略调用 close(),这不是编译时错误,因此 eclipse 不突出显示。