سؤال

Imagine that MyOpenedFile is something wrapping file with opened streams. Then suppose this code:

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

Actual method for the question:

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

Now this is quite messy and especially error-prone (some code in finally block might be very hard to get called in unit tests, for example). For example in C++, destructor would take care of cleanup (either getting called by scoped pointer destructor or directly) and code would be much cleaner.

So, is there better/nicer/cleaner way to wrap above piece of business logic code, so that any exceptions get propagated but both files f1 and f2 get closed (or at least close is attempted on both, even if it fails)?

Also answers pointing to any open source libraries such as Apache Commons, providing nice wrappers are welcome.

هل كانت مفيدة؟

المحلول

A file is a wrapper for a String which contains a file name which may or may not exist. It is stateless so you don't need to close it.

A resource you need to close is FileInputStream or BufferedReader and you can close these implicitly with ARM in Java 7

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

}

This will close br whent he block exits.

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

نصائح أخرى

Take a look at The try-with-resources Statement which will close resources after the try-block ends.

The File class you use does not seem to be java.io.File because it does not have any close() method. In that case make sure that your own File class implements Closeable to make it work with 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();
}

You dont need to close Files (which are representations of files on the file system) as mentioned here:

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

I assume you are asking more about the File Streams/Readers?

In which case java 7 has a nice new feature: http://www.vineetmanohar.com/2011/03/java-7-try-with-auto-closable-resources/

If you are working on an older version of java I'd just keep it simple with this:

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

    // do stuff

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

An option that comes automatically to my head is: Separate the code that handles files, from the code that does any processing. In this way you can encapsulate the nasty code that handles does the open, close and exception handling.

The other bit is that the sample you have does a lot of extra, unneeded steps

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

You don't need to set the File instances to null. If you try to use them, you'll get an exception.

I don wonder what File object you're using. The standard File class in java doesn't have a close() method.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top