如果在打开新的IO流之间处理IO流,是使用单个try-finally块还是使用嵌套的try-with-resources



所以在一些方法中,我将打开一个新的IO流,用它做一些处理,然后使用该流作为输入打开另一个IO流。我不相信我可以使用一个单一的尝试资源块,因为第一个IO流的处理处于打开第一个和第二个流之间。那么,使用单个try-catch-finally块来打开和关闭这些流,或者使用嵌套的try-with-resources块来打开和关闭这些流,这是更好的(从编码设计的角度来看)吗?我知道,如果在第一个和第二个IO流之间没有处理,最好在一个try-with-resources块中打开所有三个流。

一个简单的例子如下:

Try-Catch-Finally

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
   }
}

Try-with-resources

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,但在该尝试块中打开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的唯一方法是将其放在最后一个块中?

您似乎不知道,尝试使用资源为您做了什么。它不仅确保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;
}

现在再考虑一下,重写try with resources语句中的any是否可以创建更整洁的代码。即使没有正确处理close语句,你的替代方法与资源语句嵌套的try已经在代码大小上更大,更复杂,并且扩展了变量的范围,超出了它们的实际使用范围。

相反,嵌套的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
        }
    }
}

这可能是基于意见的,但我当然更喜欢尽可能使用"使用资源进行尝试"。这清楚地显示了可关闭资源使用的范围,使程序逻辑更容易理解。如果你担心嵌套的try-with-resources块,考虑将内部块提取到单独的方法中。

同样,如果您有流作为参数传递(在您的示例中为is),关闭它通常不是一个好主意。如果调用者创建了这个流,关闭它通常是调用者的责任(最好在调用者方法中使用try-with-resource语句)。最后,捕获Throwable并不是一个好主意。

相关内容

  • 没有找到相关文章

最新更新