题 尝试使用资源与Try-Catch


我一直在看代码,我已经看过尝试资源。我以前使用过标准的try-catch语句,看起来它们做同样的事情。所以我的问题是 尝试使用资源与Try-Catch  这些之间有什么区别,哪个更好。

这是一个资源尝试:

objects jar = new objects("brand");
objects can= new objects("brand");

try (FileOutputStream outStream = new FileOutputStream("people.bin")){
    ObjectOutputStream stream = new ObjectOutputStream(outStream);

    stream.writeObject(jar);
    stream.writeObject(can);

    stream.close();
} catch(FileNotFoundException e) {
    System.out.println("sorry it didn't work out");
} catch(IOException f) {
    System.out.println("sorry it didn't work out");
}

19
2017-10-22 19:58


起源


区别在于您不需要在try-wth-resource中调用stream.close()。如果你有一个关闭它的finally子句,它会被自动调用。在try-with-resouce子句中只能使用实现Closeable或AutoCloseable的对象。 - sturcotte06
你不需要(或者很可能不应该)打电话 stream.close(); 在 try{..} 部分。它应该在 finally try-with-resources将为您处理的部分(BTW try-with-resources可以处理多个资源)。 - Pshemo


答案:


try-with-resources的要点是确保资源被关闭,而不需要应用程序代码。但是,有一些更好的要点需要考虑。

当你不使用try-with-resources时,可能存在一个称为异常屏蔽的陷阱。当try块中的代码抛出异常,并且finally中的close方法也抛出异常时,try块抛出的异常会丢失,并且finally中抛出的异常会被传播。这通常是不幸的,因为关闭时抛出的异常是无用的,而有用的异常是信息性异常。使用try-with-resources关闭资源可以防止发生任何异常屏蔽。

作为确保异常屏蔽不会丢失重要异常信息的一部分,当开发try-with-resources时,他们必须决定如何处理close方法抛出的异常。

使用try-with-resources,如果try块抛出异常并且close方法也抛出异常,那么 close块的异常会被添加到原始异常中

...在某些情况下,可以在兄弟代码块中抛出两个独立的异常,特别是在try-with-resources语句的try块和编译器生成的finally块中,它关闭资源。在这些情况下,只能传播一个抛出的异常。在try-with-resources语句中,当存在两个此类异常时,将传播源自try块的异常,并将finally块中的异常添加到由try块中的异常抑制的异常列表中。作为异常展开堆栈,它可以累积多个抑制异常。

另一方面,如果您的代码正常完成但是您正在使用的资源在关闭时抛出异常,那么该异常(如果try块中的代码抛出任何内容会被抑制)会被抛出。因此,如果您有一些JDBC代码,其中ResultSet或PreparedStatement由try-with-resources关闭,则可以抛出JDBC对象关闭时由于某些基础结构故障导致的异常,并且可以回滚否则成功完成的操作。

没有try-with-resources,是否抛出close方法异常取决于应用程序代码。如果在try块抛出异常时它被抛出finally块,则finally块中的异常将掩盖另一个异常。但是开发人员可以选择捕获关闭时抛出的异常,而不是传播它。


31
2017-10-22 20:15



我希望有一个简单的方法可以让“finally”块找出从“try”中抛出的异常(如果有的话),以便允许相同类型的传播 - 清理 - 例外 - 如果没有其他用户代码中的待定逻辑。 - supercat


你错过了什么, finally 块。该 try-with-resouces 将使它像,

FileOutputStream outStream = null;
try {
  outStream = new FileOutputStream("people.bin");
  ObjectOutputStream stream = new ObjectOutputStream(outStream);

  stream.writeObject(jar);
  stream.writeObject(can);

  stream.close();
} catch(FileNotFoundException e) {
    System.out.println("sorry it didn't work out");
} catch(IOException f) {
    System.out.println("sorry it didn't work out");
} finally {
  if (outStream != null) { 
    try { 
      outStream.close(); 
    } catch (Exception e) {
    } 
  }
}

这意味着你真的想要像(决不 燕子例外),

try (FileOutputStream outStream = new FileOutputStream("people.bin");
     ObjectOutputStream stream = new ObjectOutputStream(outStream);) {
  stream.writeObject(jar);
  stream.writeObject(can);
  // stream.close(); // <-- closed by try-with-resources.
} catch(FileNotFoundException e) {
    System.out.println("sorry it didn't work out");
    e.printStackTrace();
} catch(IOException f) {
    System.out.println("sorry it didn't work out");
    e.printStackTrace();
}

5
2017-10-22 20:01



stream.close();在try块中是不必要的,因为无论如何都要在finally块中关闭流。 - nullptr
@Meraman我在答案的最后部分注意到了。请注意OP的问题 没有  finally 块。 - Elliott Frisch


唯一的区别是try-resource正在自动添加 resource.close(); 就像你会做的那样 finally 块


1
2017-10-22 20:01





实现java.lang.AutoCloseable或java.io.Closeable的任何对象(类或其超类) 只能在try-with-resource子句中使用。 AutoClosable接口是父接口,Closable接口扩展AutoClosable接口.AutoClosable接口有方法close,抛出Exception,而Closable接口有抛出IOException的方法。 我们也可以捕获并最终阻塞,然后像普通的try,catch和finally一样尝试使用资源,但是一旦在try-with-resource子句中声明的资源关闭,catch和finally块才会被执行。


0
2018-01-23 11:22