如何正确关闭输入流?
How to properly close input streams?
有两种方法可以做同样的事情。第一个:
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);
}
哪种方法更正确?
第一个更正确,因为第二个在抛出异常时不会关闭 InputStreamReader
和 BufferedReader
,而第一个示例使用 try-with-resources 语句 (https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html).
为了使第一个示例正确,您应该将关闭资源的行移动到 finally
子句:
try (var result = executor.execPipelineAndGetInputStream(builders)) {
var input = new InputStreamReader(result);
var reader = new BufferedReader(input);
var ip = reader.lines().collect(Collectors.joining());
return ip;
} catch (IOException exception) {
throw new NotFoundException(name);
} finally {
input.close();
reader.close();
}
第二个永远不正确。 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);
}
}
在这 3 个选项中,您会陷入争论;第一个选项似乎不错;这些所谓的 'filter streams' 的实现(那些是 readers/writers/outputstreams/inputstreams 那个 'wrap' 另一个流)有一个协议,即 close()
ing 它们将关闭它们包装的东西。因此,通常 #1 看起来很好,但是如果在过滤器流的构造函数中发生异常,那么您将泄漏资源。这些异常会发生吗?通常不可能,但并非总是如此,这里有一个导致常用过滤器流在构造中崩溃的简单方法:
new InputStreamReader(someData, "some non existing charset");
因此,我强烈反对第一种。剩下 2 号门和 3 号门:真的没关系;我认为第二个可能是最可读的,但是第二个选项的问题是各种 IDE 和 linting 工具会抱怨它,他们很难区分资源代表流和 filters/memory-only 喜欢流媒体。这不是他们的错,真的:他们怎么可能知道您的 execPipelineAndGetInputStream
方法返回的 InputStream 应该是 'thing you need to close' 或 'thing you can close but it doesnt matter' 还是 'thing you should not be closing at all'?
有两种方法可以做同样的事情。第一个:
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);
}
哪种方法更正确?
第一个更正确,因为第二个在抛出异常时不会关闭 InputStreamReader
和 BufferedReader
,而第一个示例使用 try-with-resources 语句 (https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html).
为了使第一个示例正确,您应该将关闭资源的行移动到 finally
子句:
try (var result = executor.execPipelineAndGetInputStream(builders)) {
var input = new InputStreamReader(result);
var reader = new BufferedReader(input);
var ip = reader.lines().collect(Collectors.joining());
return ip;
} catch (IOException exception) {
throw new NotFoundException(name);
} finally {
input.close();
reader.close();
}
第二个永远不正确。 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);
}
}
在这 3 个选项中,您会陷入争论;第一个选项似乎不错;这些所谓的 'filter streams' 的实现(那些是 readers/writers/outputstreams/inputstreams 那个 'wrap' 另一个流)有一个协议,即 close()
ing 它们将关闭它们包装的东西。因此,通常 #1 看起来很好,但是如果在过滤器流的构造函数中发生异常,那么您将泄漏资源。这些异常会发生吗?通常不可能,但并非总是如此,这里有一个导致常用过滤器流在构造中崩溃的简单方法:
new InputStreamReader(someData, "some non existing charset");
因此,我强烈反对第一种。剩下 2 号门和 3 号门:真的没关系;我认为第二个可能是最可读的,但是第二个选项的问题是各种 IDE 和 linting 工具会抱怨它,他们很难区分资源代表流和 filters/memory-only 喜欢流媒体。这不是他们的错,真的:他们怎么可能知道您的 execPipelineAndGetInputStream
方法返回的 InputStream 应该是 'thing you need to close' 或 'thing you can close but it doesnt matter' 还是 'thing you should not be closing at all'?