Hédi Ghédiri Hédi Ghédiri - 16 days ago 5
Java Question

java how to ensure a file gets closed

I have a class that opens a file in constructor, writes in file during a call to a method. Where shall I close the file ?
The class implements a general interface that has only one method and I shall not add public methods.

public interface I {
void makeChange();
}

public class C implements I {
FileWriter f;
PrintWriter p;
public C() {
f = new FileWriter("log.txt");
p = new PrintWriter(p);
}
@Override
public void makeChange() {
p.println("something");
p.flush();
}
}


I am not allowed to add a public method endChanges().

Also the class cannot know when the changes end.

I am allowed to change the way the Constructor and makeChange() work.

I tried finalize() but it didn't even run.

EDIT.
The Interface I is implemented by many classes.
Some of them do not need a file, thus they do not need a closeFile() method.

The goal is to make the same code run for all the implementations:

public static void main(String args[]) {
I c1 = new C();
c1.makeChange();
I c2 = new D(); // D is an implementation of I that doesn't handle a file
c2.makeChange();
}

Answer

A design that prevents you from adding public method endChanges() is inherently wrong and prevents you from doing this the right way.

If this is some kind of homework or a quiz (or worse still, a quiz-homework), the "correct" answer is probably to use finalize(). But as you have noticed yourself, this method may not even run (e.g. if the JVM stops before it needs to free the object). In that simple case, it's OK because it will close the file at that same time, but generally the use of finalize() is discouraged for exactly the reason you've run into.


The correct approach is for the class to implement Closeable interface and provide a close() methods for the user to invoke when done. Since you want to invoke multiple calls on the file between opening and closing it, this is the standard approach.

(Editted to add): If you have multiple implementations and some of them need any cleanup logic and others do not, it is absolutely OK for the interface to have a cleanup (close) method that the user must call but that some implementations leave empty.


If you need to be absolutely sure the user does not forget to close the file, you could instaed create a doWithFile() method that accepts a callback to perform on the file, opens the file, performs the callback then closes the file.