本文介绍了在Callable.call中没有关闭的BufferedReader会发生什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有三个问题。

要解释,我正在审核某人的代码,并注意到 BufferedReader 有时没有关闭。通常,Eclipse会发出警告,这是一个潜在的内存泄漏(我修复它)。但是,在Callable内部类中,没有警告。

To explain, I was reviewing someone's code, and noticed BufferedReaders 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.

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开发人员,所以我的第一个想法是,这是有意的...但是可能是他们在写作时匆忙,只是忽略了它。

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.

我的问题是:


  1. 为什么Eclipse不强调这一点(可以通过答案回答以下问题)?

  1. Why does Eclipse not highlight this (which may be answered by the answer to the following questions)?

如果在call()方法中关闭,最坏的情况是什么? (我不能想到一个很好的理由...我一直在寻找一段时间...但也许是故意不关闭BufferedReader)

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)

如果BufferedReader是 在内部类中关闭,那么最糟糕的是什么?

What is the worst that could happen if the BufferedReader is not closed within the inner class?


推荐答案

我会说,因为他们在一个给定的周围创建一个 BufferedReader InputStream ,代码是安全的,不会调用 close()。调用 close()的代码应该始终是使用try / finally创建流并完成的代码。

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.

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.

哦,而$ IOException 不可能发生,因为流是来自另一个进程。这不可能发生,除非发生一些不可恢复的错误。尽管如此,仍然不会以异常方式记录异常。

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.

编辑以解决您的关于混合答案的评论:

让我们使用输出流和这个例子:

Let's use an output stream and BufferedWriter as an example this time:

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 的代理,并且实际上向文件中写入单个。当然,这个逻辑可能会更复杂一些,比如把一个对象变成一个 String 并编写它。这使得 main 方法更容易阅读。

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.

现在,如果我们关闭BufferedWriter ?

Now, what if instead, we closed the 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 调用。始终关闭创建它们的流,而不是通过它们的地方是很好的做法。这可能是最好的,但后来尝试更改该代码可能会导致错误。如果我开始只用一个 writeLine 调用不好的方法,有人想添加第二个,他们必须重构代码,以便 writeLine 没有关闭流。

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.

另外请注意,技术上, BufferedWriter 不是实际处理系统资源, FileOutputStream 是,所以你应该关闭实际资源。

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.

所以,经验法则:只关闭您创建它们的流,并始终在try / finally块中创建和关闭(或Java 7的awesome ,它为您的关闭。)

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).

这篇关于在Callable.call中没有关闭的BufferedReader会发生什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-29 20:39