首页 > 解决方案 > 如何正确关闭输入流?

问题描述

有两种方法可以做同样的事情。首先:

public String getIpByName(String name) {
       var builders = NetworkUtil.buildProcess(name);
    try (var ip = new BufferedReader(new InputStreamReader(executor.execPipelineAndGetInputStream(builders)))) {
        return ip.lines().collect(Collectors.joining());
    } catch (IOException exception) {
        throw new NotFoundException(name);
    }
}

第二:

public String getIpByName(String name) {
    var builders = NetworkUtil.buildProcess(name);
    try (var result = executor.execPipelineAndGetInputStream(builders)) {
        var input = new InputStreamReader(result);
        var reader = new BufferedReader(input);
        var ip = reader.lines().collect(Collectors.joining());
        input.close();
        reader.close();
        return ip;
    } catch (IOException exception) {
        throw new NotFoundException(name);
    }

哪种方法更正确?

标签: javatry-catchinputstreambufferedreaderinputstreamreader

解决方案


第二个永远不正确。这些电话要么close()很重要,要么不重要。如果它们很重要,它们应该是 try/finally-ied 或 try-with-resourced。如果它们不重要,它们就不重要,你不应该费心写这些陈述。

因此,我们有 3 个备选方案,而不是 2 个,并且只有您的第一个备选方案保持不变:

第二:

public String getIpByName(String name) {
    var builders = NetworkUtil.buildProcess(name);
    try (var result = executor.execPipelineAndGetInputStream(builders)) {
        var input = new InputStreamReader(result);
        var reader = new BufferedReader(input);
        return reader.lines().collect(Collectors.joining());
    } catch (IOException exception) {
        throw new NotFoundException(name);
    }
}

还有第三个,使用 try-with-resources 的资源链接功能:

public String getIpByName(String name) {
    var builders = NetworkUtil.buildProcess(name);
    try (var result = executor.execPipelineAndGetInputStream(builders);
      var input = new InputStreamReader(result);
      var reader = new BufferedReader(input)) {

        return reader.lines().collect(Collectors.joining());
    } catch (IOException exception) {
        throw new NotFoundException(name);
    }
}

在这三个选项中,您会进行一些辩论;第一个选项看起来不错;这些所谓的“过滤流”(它们是“包装”另一个流的读取器/写入器/输出流/输入流)的实现具有close()它们将关闭它们包装的东西的交易。因此,通常#1 看起来不错,但是如果在过滤器流的构造函数中发生异常,那么您就会泄漏资源。会不会出现这些异常?通常不可能,但并非总是如此,这是导致常用过滤器流在构造中崩溃的一种简单方法:

new InputStreamReader(someData, "some non existing charset");

因此,我强烈建议不要使用第一个。剩下2号门和3号门:真的没关系;我认为第二个可能是最易读的,但是第二个选项的问题是各种 IDE 和 linting 工具会抱怨它,他们很难区分代表资源的流和过滤器/内存之间的区别流式样。这不是他们的错,真的:他们怎么可能知道你的execPipelineAndGetInputStream方法返回的 InputStream 是否应该是“你需要关闭的东西”或“你可以关闭但没关系的东西”或“你不应该关闭的东西”完全没有?


推荐阅读