是否有一种干净的方法来为Java对象提供破坏范围?

时间:2012-11-01 10:13:47

标签: java exception file-io raii resource-cleanup

想象一下,MyOpenedFile是包含已打开流的文件的东西。然后假设这段代码:

// method in an Util class
static void safeClose(MyOpenedFile f) {
  if (f != null) {
    try {
      f.close();
    } catch(IOException ex) { /* add logging or console output */ }
  }
}

问题的实际方法:

void doSomeFileOperation(...) throws IOException, ... {
    MyOpenedFile f1 = null;
    MyOpenedFile f2 = null;
    try {

      /* method's "business logic" code beings */
      f1 = new MyOpenedFile(...);
      //do stuff
      f2 = new MyOpenedFile(...);
      // do stuff
      f1.close(); f1 = null;
      // do stuff with f1 closed
      f2.close(); f2 = null;
      // do stuff with f2 closed
      /* method's "business logic" code ends */

    } finally {
      Util.safeClose(f1); f1 = null;
      Util.safeClose(f2); f2 = null; 
    }
}

现在这非常混乱,特别容易出错(例如,在单元测试中,finally块中的某些代码可能很难被调用)。例如,在C ++中,析构函数将负责清理(由scoped指针析构函数调用或直接调用),代码将更加清晰。

那么,是否有更好/更好/更清洁的方式来包装上面的业务逻辑代码,以便传播任何异常,但文件f1f2都关闭(或至少关闭是尝试两者,即使它失败了)?

也指向任何开源库,如Apache Commons,欢迎提供好的包装。

4 个答案:

答案 0 :(得分:4)

文件是String的包装器,其中包含可能存在或不存在的文件名。它是无国籍的,所以你不需要关闭它。

您需要关闭的资源是FileInputStream或BufferedReader,您可以在Java 7中使用ARM隐式关闭这些资源

try(BufferedReader br = new BufferedReader(new FileReader(file))) {

}

当他阻止退出时,这将关闭br

http://www.oracle.com/technetwork/articles/java/trywithresources-401775.html

答案 1 :(得分:1)

看一下The try-with-resources Statement,它将在try-block结束后关闭资源。

您使用的File类似乎不是java.io.File,因为它没有任何close()方法。在这种情况下,请确保您自己的File类实现Closeable以使其与ARM一起使用。

try (FileInputStream f1 = new FileInputStream("test1.txt");
     FileInputStream f2 = new FileInputStream("test2.txt")) {
    // Some code
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

答案 2 :(得分:1)

你不需要关闭文件(这是文件系统上文件的表示),如下所述:

Do I need to close files I perform File.getName() on?

我假设您要求更多关于文件流/读者的信息?

在这种情况下,java 7有一个很好的新功能: http://www.vineetmanohar.com/2011/03/java-7-try-with-auto-closable-resources/

如果你正在使用旧版本的java,我只想简单地说:

void doSomeFileOperation(...) throws IOException, ... {
  FileInputStream f1 = null;
  FileInputStream f2 = null;
  try {

    // do stuff

  } finally {
    Util.safeClose(f1); 
    Util.safeClose(f2); 
  }
}

答案 3 :(得分:0)

自动出现的选项是:将处理文件的代码与执行任何处理的代码分开。通过这种方式,您可以封装处理打开,关闭和异常处理的讨厌代码。

另一点是你的样本做了很多额外的,不必要的步骤

void doSomeFileOperation(...) throws IOException, ... {
    File f1 = null;
    File f2 = null;
    try {
      f1 = new File(...);
      f2 = new File(...);
      // callback to another class / method that does the real work
    } finally {
      Util.safeClose(f1);
      Util.safeClose(f2);
    }
}

您无需将File实例设置为null。如果您尝试使用它们,您将获得例外。

我不知道你正在使用的File对象。 java中的标准File类没有close()方法。