我有三个问题。
解释一下,我正在审查某人的代码,并注意到 BufferedReader
有时没有被关闭。通常,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;
}
}
}
编写代码的人都是经验丰富的 Java 开发人员,所以我的第一个想法是这是故意的......但也可能是他们编写代码时匆忙而忽略了它。
我的问题是:
为什么 Eclipse 不突出显示这一点(可以通过以下问题的答案来回答)?
如果它在 call() 方法中关闭,可能发生的最坏情况是什么? (我想不出一个很好的理由......我已经搜索了一段时间......但也许是故意不关闭BufferedReader)
如果 BufferedReader 不在内部类中关闭,可能发生的最坏情况是什么?
最佳答案
我想说的是,由于他们围绕给定的 InputStream
创建了一个 BufferedReader
,所以代码不调用 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);
}
另一个注意事项:您的代码似乎正在记录其他进程的输出。无论如何,您可能无法关闭流。如果不亲自测试,我不确定如果关闭来自另一个进程的流会发生什么情况。
哦,IOException
不太可能发生,因为流来自另一个进程。除非发生一些不可恢复的错误,否则这不太可能发生。不过,以某种方式记录异常仍然不是一个坏主意。
编辑以解决您对混合答案的评论:
让我们使用一个输出流和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);
}
这行得通。 writeLine 方法用作创建 writer
并实际将单个 line
写入文件的委托(delegate)。当然,这个逻辑可以是更复杂的东西,比如把一个对象变成一个String
然后写入。这也使 main
方法更易于阅读。
现在,如果我们关闭 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();
}
}
尝试用它运行它,每次在第二次 writeLine
调用时它都会失败。最好始终在创建它们的地方关闭流,而不是在它们经过的地方关闭流。最初可能没问题,但稍后尝试更改该代码可能会导致错误。如果我一开始只有 1 个 writeLine
调用,但其他人想添加第二个,他们就必须重构代码,这样 writeLine
就不会无论如何关闭流。近距离快乐可能会导致头痛。
另请注意,从技术上讲,BufferedWriter
并不是您系统资源的实际句柄,FileOutputStream
才是,因此无论如何您都应该关闭实际资源。
因此,经验法则:仅在创建流时关闭流,并且始终在 try/finally block 中进行创建和关闭(或 Java 7 的出色 try/resource block ,它会为您完成关闭)。
关于java - 在 callable.call 中没有关闭的 BufferedReader 会发生什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12203291/