如果在打开新流之间处理 IO 流,是使用单个 try-finally 块还是使用嵌套的 try-with-resources 更好?
If processing IO streams between opening new ones, is it better to have a single try-finally block or have nested try-with-resources?
所以在某些方法中,我将打开一个新的 IO 流,用它做一些处理,然后使用该流作为输入来打开另一个 IO 流。我不相信我可以使用单个 try-with-resources 块,因为第一个 IO 流的处理是在打开第一个和第二个流之间进行的。因此,话虽如此,使用单个 try-catch-finally 块来打开和关闭这些流还是使用嵌套的 try-with-resources 块来打开和关闭流会更好(在编码设计意义上)?我知道如果第一个和第二个 IO 流之间没有处理,最好在一个 try-with-resources 块中打开所有三个流。
下面是一个简单的例子:
尝试-捕捉-最后
void someMethod(InputStream is) throws SomeException {
SomeIOStream io1 = null;
SomeIOStream io2 = null;
SomeIOStream io3 = null;
try{
io1 = new SomeIOStream( someSortOfProcessing() );
io1.moreStreamProcessing();
io2 = new SomeIOStream( someSortOfProcessing(io1) );
io3 = new SomeIOStream (is);
//do stuff with io2 and io3
} catch (Throwable t) {
//Exception Handling
} finally {
//closing streams io3, io2, io1, is
}
}
尝试资源
void someMethod(InputStream is) throws SomeException {
try ( SomeIOStream io1 = new SomeIOStream( someSortOfProcessing() ) ){
io1.moreStreamProcessing();
try ( SomeIOStream io2 = new SomeIOStream( someSortOfProcessing(io1) );
SomeIOStreeam io3 = new SomeIOStream (is); ){
//do stuff with io2 and io3
}
} catch (Throwable t) {
//Exception Handling
} finally {
//closing stream is
}
}
对我来说,第一个看起来更简洁,但第二个具有 try-with-resources 块的优点。当然,另一种 替代方法是使用 try-with-resources 打开初始 io1,但在该 try-block 中打开 io2 和 io3。那么第三种混合方法会比上面两种更好吗?
混合方法
void someMethod(InputStream is) throws SomeException {
SomeIOStream io1 = null;
SomeIOStream io2 = null;
SomeIOStream io3 = null;
try (SomeIOStream io1 = new SomeIOStream( someSortOfProcessing() ) ){
io1.moreStreamProcessing();
io2 = new SomeIOStream( someSortOfProcessing(io1) );
io3 = new SomeIOStream (is);
//do stuff with io2 and io3
} catch (Throwable t) {
//Exception Handling
} finally {
//closing streams io3, io2, is
}
}
另外还有一个问题,我认为关闭 InputStream is
的唯一方法是将其放在 finally-block 中是否正确?
这可能是基于意见的,但我当然更愿意尽可能多地使用 try-with-resources。这清楚地显示了可关闭资源使用的范围,使程序逻辑更容易理解。如果您担心嵌套的 try-with-resources 块,请考虑将内部块提取到单独的方法中。
此外,如果您将流作为参数传递(在您的示例中为 is
),关闭它通常不是一个好主意。如果调用者创建了这个流,调用者通常有责任关闭它(最好在调用者方法中使用 try-with-resource 语句)。最后 catch the Throwable
.
很少是个好主意
看来,您并没有意识到 try with resources 为您做了什么。它不仅确保 close()
被调用,还确保在 close()
因异常而失败的情况下,它不会隐藏初始异常(如果有的话),而是记录使用 addSuppressed
.
的次要异常
所以相当于
try(Resource r = allocation ) {
…
}
是
{
Resource r = allocation;
Throwable primary = null;
try {
…
}
catch(Throwable t) { primary = t; }
finally {
if(r != null) try {
r.close();
}
catch(Throwable t) {
if(primary!=null) primary.addSuppressed(t); else primary=t;
}
}
if(primary!=null) throw primary;
}
现在再次考虑是否重写 any try with resources 语句,手动执行此操作,创建更清晰的代码。即使没有正确处理关闭,嵌套 try with resource 语句的替代方案在代码量上也已经更大、更复杂并且变量的范围超出了它们的实际用途。
相比之下,嵌套的 try with resource 语句准确地反映了您在做什么,在嵌套范围内使用资源。如果您删除有问题的包罗万象的部分并关闭传入资源,它会变得更好。
请注意,在极少数情况下,关闭传入资源可能是可以接受的,例如如果它是 private
方法并且行为有详细记录。但即便如此,你也不应该求助于 finally
:
void someMethod(InputStream incomingIs) throws SomeException {
try(InputStream is=incomingIs;// it must be documented that we will close incomingIs
SomeIOStream io1 = new SomeIOStream(someSortOfProcessing()) ) {
io1.moreStreamProcessing();
try(SomeIOStream io2 = new SomeIOStream(someSortOfProcessing(io1));
SomeIOStreeam io3 = new SomeIOStream (is) ) {
//do stuff with io2 and io3
}
}
}
所以在某些方法中,我将打开一个新的 IO 流,用它做一些处理,然后使用该流作为输入来打开另一个 IO 流。我不相信我可以使用单个 try-with-resources 块,因为第一个 IO 流的处理是在打开第一个和第二个流之间进行的。因此,话虽如此,使用单个 try-catch-finally 块来打开和关闭这些流还是使用嵌套的 try-with-resources 块来打开和关闭流会更好(在编码设计意义上)?我知道如果第一个和第二个 IO 流之间没有处理,最好在一个 try-with-resources 块中打开所有三个流。
下面是一个简单的例子:
尝试-捕捉-最后
void someMethod(InputStream is) throws SomeException {
SomeIOStream io1 = null;
SomeIOStream io2 = null;
SomeIOStream io3 = null;
try{
io1 = new SomeIOStream( someSortOfProcessing() );
io1.moreStreamProcessing();
io2 = new SomeIOStream( someSortOfProcessing(io1) );
io3 = new SomeIOStream (is);
//do stuff with io2 and io3
} catch (Throwable t) {
//Exception Handling
} finally {
//closing streams io3, io2, io1, is
}
}
尝试资源
void someMethod(InputStream is) throws SomeException {
try ( SomeIOStream io1 = new SomeIOStream( someSortOfProcessing() ) ){
io1.moreStreamProcessing();
try ( SomeIOStream io2 = new SomeIOStream( someSortOfProcessing(io1) );
SomeIOStreeam io3 = new SomeIOStream (is); ){
//do stuff with io2 and io3
}
} catch (Throwable t) {
//Exception Handling
} finally {
//closing stream is
}
}
对我来说,第一个看起来更简洁,但第二个具有 try-with-resources 块的优点。当然,另一种 替代方法是使用 try-with-resources 打开初始 io1,但在该 try-block 中打开 io2 和 io3。那么第三种混合方法会比上面两种更好吗?
混合方法
void someMethod(InputStream is) throws SomeException {
SomeIOStream io1 = null;
SomeIOStream io2 = null;
SomeIOStream io3 = null;
try (SomeIOStream io1 = new SomeIOStream( someSortOfProcessing() ) ){
io1.moreStreamProcessing();
io2 = new SomeIOStream( someSortOfProcessing(io1) );
io3 = new SomeIOStream (is);
//do stuff with io2 and io3
} catch (Throwable t) {
//Exception Handling
} finally {
//closing streams io3, io2, is
}
}
另外还有一个问题,我认为关闭 InputStream is
的唯一方法是将其放在 finally-block 中是否正确?
这可能是基于意见的,但我当然更愿意尽可能多地使用 try-with-resources。这清楚地显示了可关闭资源使用的范围,使程序逻辑更容易理解。如果您担心嵌套的 try-with-resources 块,请考虑将内部块提取到单独的方法中。
此外,如果您将流作为参数传递(在您的示例中为 is
),关闭它通常不是一个好主意。如果调用者创建了这个流,调用者通常有责任关闭它(最好在调用者方法中使用 try-with-resource 语句)。最后 catch the Throwable
.
看来,您并没有意识到 try with resources 为您做了什么。它不仅确保 close()
被调用,还确保在 close()
因异常而失败的情况下,它不会隐藏初始异常(如果有的话),而是记录使用 addSuppressed
.
所以相当于
try(Resource r = allocation ) {
…
}
是
{
Resource r = allocation;
Throwable primary = null;
try {
…
}
catch(Throwable t) { primary = t; }
finally {
if(r != null) try {
r.close();
}
catch(Throwable t) {
if(primary!=null) primary.addSuppressed(t); else primary=t;
}
}
if(primary!=null) throw primary;
}
现在再次考虑是否重写 any try with resources 语句,手动执行此操作,创建更清晰的代码。即使没有正确处理关闭,嵌套 try with resource 语句的替代方案在代码量上也已经更大、更复杂并且变量的范围超出了它们的实际用途。
相比之下,嵌套的 try with resource 语句准确地反映了您在做什么,在嵌套范围内使用资源。如果您删除有问题的包罗万象的部分并关闭传入资源,它会变得更好。
请注意,在极少数情况下,关闭传入资源可能是可以接受的,例如如果它是 private
方法并且行为有详细记录。但即便如此,你也不应该求助于 finally
:
void someMethod(InputStream incomingIs) throws SomeException {
try(InputStream is=incomingIs;// it must be documented that we will close incomingIs
SomeIOStream io1 = new SomeIOStream(someSortOfProcessing()) ) {
io1.moreStreamProcessing();
try(SomeIOStream io2 = new SomeIOStream(someSortOfProcessing(io1));
SomeIOStreeam io3 = new SomeIOStream (is) ) {
//do stuff with io2 and io3
}
}
}