GLa*_*DOS 8 java eclipse callable inner-classes bufferedreader
我有三个问题.
为了解释,我正在审查某人的代码,并注意到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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
编写代码的人都是经验丰富的Java开发人员,所以我首先想到的是它是有意的......但是当他们编写代码并且忽略它时,他们可能很匆忙.
我的问题是:
为什么Eclipse没有强调这一点(可以通过以下问题的答案回答)?
如果在call()方法中关闭可能发生的最坏情况是什么?(我想不出一个很好的理由......而且我一直在寻找...但也许是故意不关闭BufferedReader)
如果BufferedReader 在内部类中没有关闭,可能会发生什么?
我会说,因为他们正在创建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);
}
Run Code Online (Sandbox Code Playgroud)
另一个注意事项:您的代码似乎是从其他进程记录输出.无论如何,你可能无法关闭流.没有自己测试,我不确定如果你从另一个进程关闭一个流会发生什么.
哦,并且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);
}
Run Code Online (Sandbox Code Playgroud)
这有效.writeLine方法用作创建writer和实际写入line文件的委托.当然,这种逻辑可能更复杂,例如将对象转换为a 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();
}
}
Run Code Online (Sandbox Code Playgroud)
尝试使用它运行它,并且每次第二次writeLine调用时都会失败.最好始终关闭创建它们的流,而不是它们通过的地方.最初可能没问题,但之后尝试更改该代码可能会导致错误.如果我开始只writeLine使用错误的方法进行1次调用而其他人想要添加第二次调用,则他们必须重构代码,以便writeLine无论如何都不会关闭流.近距离接触可能导致头痛.
另请注意,从技术上讲,BufferedWriter它不是系统资源的实际句柄FileOutputStream,因此您应该关闭实际资源.
因此,经验法则:只关闭您创建它们的流,并始终在try/finally块(或Java 7的真棒尝试/资源块,您为此完成关闭)中创建和关闭.