java - 在 callable.call 中没有关闭的 BufferedReader 会发生什么?

标签 java eclipse inner-classes bufferedreader callable

我有三个问题。

解释一下,我正在审查某人的代码,并注意到 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 开发人员,所以我的第一个想法是这是故意的......但也可能是他们编写代码时匆忙而忽略了它。

我的问题是:

  1. 为什么 Eclipse 不突出显示这一点(可以通过以下问题的答案来回答)?

  2. 如果它在 call() 方法中关闭,可能发生的最坏情况是什么? (我想不出一个很好的理由......我已经搜索了一段时间......但也许是故意不关闭BufferedReader)

  3. 如果 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/

相关文章:

java - 将 org.json.JSONObject 转换为 javax.sql.rowset.serial.SerialBlob 的最佳方法是什么?

java - 检查您要连接的端口是否正在使用

java - 如何 - 使用 eclipse 进行 github 两因素身份验证

java - 无法访问内部类变量

java - 嵌套 Java 内部类的深度超过一层是否合理?

java - 用spring创建内部类

java - getBaseContext 还是 getContext?它们有何不同?

java - AtomicInteger 原子的

java - 如何在表格布局中使用 richfaces 的自动完成功能?

java - 有没有一种方法可以通过提供不同关键字、 block 开始等的列表来向 Eclipse 添加非常简单的代码突出显示?