当前位置: 首页 > 面试题库 >

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

淳于禄
2023-03-14
问题内容

我有三个问题。

为了解释,我正在查看某人的代码,并注意到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,可能发生的最坏情况是什么?


问题答案:

我要说的是,由于他们正在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);
}

另一个注意事项:您的代码似乎正在记录其他进程的输出。无论如何,您可能无法关闭流。如果不自己测试,我不确定如果关闭另一个进程的流会发生什么。

哦,这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文件并将其实际写入文件的委托。当然,这种逻辑可能更复杂,例如将一个对象变成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();
    }
}

尝试以此运行它,它将在每次第二次writeLine调用时失败。最好始终在创建流的地方而不是在传递流的地方关闭流。最初可能没问题,但是随后尝试更改该代码可能会导致错误。如果我只writeLine使用坏方法进行了一次调用,而其他人想添加第二个调用,那么他们将不得不重构代码,以致writeLine始终无法关闭流。变得近距离开心可能会引起头痛。

还要注意,从技术上讲,BufferedWriteris不是系统资源的实际句柄,FileOutputStream而是is,因此无论如何,您都应该关闭实际资源。

因此,经验法则:仅在创建流的地方关闭流,并始终在try / finally块(或Java 7很棒的try /
resource块
,为您关闭)中进行创建和关闭。



 类似资料:
  • 假设我有一个普通的应用程序,其中我正在使用ApplicationContext ApplicationContext=new FileSystemXmlApplicationContext(“bean.xml”)创建一个Spring应用程序上下文 现在,假设在这个bean.xml有Spring bean的bean定义,所以当我创建应用程序上下文时,Spring容器将为这个实例化和初始化一个对象。

  • 如果在java中执行关闭挂钩期间引发了未捕获的异常,jvm是否会立即退出,而不运行其余已注册的关闭挂钩(如果有)?从javadocs: 未捕获的异常通过调用线程ThreadGroup对象的uncaughtException方法在关闭钩子中处理,就像在任何其他线程中一样。此方法的默认实现将异常的堆栈跟踪打印到System.err并终止线程;它不会导致虚拟机退出或停止。 似乎其他关机挂钩应该运行...

  • 问题内容: 我有一个使用简单套接字在两个系统之间传递某些字符的应用程序。我的Java应用程序作为服务器运行。我建立了良好的连接,甚至传递了一条消息。但是,发送完一条消息后,我的连接关闭。 从我可以看出来的好像是在关闭时,套接字本身正在关闭吗?!这很不好,因为我有多个要在同一连接上发送的消息。 我吃饱了吗?如何在Java中维护此连接? 问题答案: 是的,关闭任何作家/读者将关闭他们包装的所有其他作家

  • 问题内容: 我注意到,如果关闭,我将无法再从键盘插入输入,因为已经关闭了。无论如何,我可以保留(删除文件时需要它),然后从键盘添加更多输入吗? 问题答案: 看起来您需要: http://commons.apache.org/io/apidocs/org/apache/commons/io/input/CloseShieldInputStream.html 在制作读者之前,先将System.in环绕

  • 相关问题,但不是我想知道的,因为我对PHPlib/函数的具体行为很好奇: 当连接在事务中间关闭时会发生什么? 当连接关闭时,未提交的事务会发生什么? 假设我有这样的代码(不管它是好的还是坏的实践): 包含提交和回滚的将被跳过,而连接将在事务启动后但在调用提交或回滚之前关闭。 该事务是否也会立即被销毁/结束/不管什么专有名词,或者它会保留下来并可能阻止来自其他服务的其他查询?

  • 编辑问题,以包括所需的行为、特定问题或错误,以及重现问题所需的最短代码。这将帮助其他人回答这个问题。 我们知道:load with memory_order_acquire,store with memory_order_release但是,我发现用gcc4.8.2,open -O2时,抛出了一个编译错误,/usr/include/c/4 . 8 . 2/atomic:199:9:error:对于