1

This problem with Java method protected void finalize() , I tried to look pervious questions about this but still can not figure it out how to solve it, So one of my project class is calling this method finalize() which is deprecated from Java 9, maybe they will remove it in further release so my company want to fix this issue and I got work on this part, which is my bad-luck. Can anyone suggest me how I can fix it, solution is simple just remove that method from the class but nobody allow me to do that because they don't want to take the risk. So I need solution for this,

I don't know how much sense it will make for you guys please, I am open for wonderful solutions for it.

private DiskCache dc;

  public void delete(DiskCacheItem item)
  {
    File f = file(item);
    if (f != null)
    {
      log.debug("Delete " + f + ": " + f.delete());
    }
    files.remove(item);
    items.remove(item);
  }

private void validate()
  {
    dc.validate(this);
  } 


public void delete()
  {
    validate();
    dc.delete(this);
  }


protected void finalize()
  {
    try { delete(); } catch (Exception e) { }
  }
Hari Sheen
  • 13
  • 3
  • 1
    There is a fundamental problem with your task: you are supposed to solve it, but not allowed to do the necessary step(s), “because they don't want to take the risk”. It seems, they have no clue about the risks of keeping this method. Recommended readings: [When is the finalize() method called in Java?](https://stackoverflow.com/q/2506488/2711488), [Can java finalize an object when it is still in scope?](https://stackoverflow.com/q/24376768/2711488), and [finalize() called on strongly reachable objects in Java 8](https://stackoverflow.com/q/26642153/2711488). In short: *remove that method*. – Holger May 03 '19 at 11:31
  • By the way, it’s highly dangerous to hide calls with an impact as `f.delete()` in a `log.debug(…);` statement. Just imagine what could happen if a programmer not aware of this subtlety will a) remove or b) copy that statement, thinking that it was just a debug output statement… – Holger May 03 '19 at 11:36

2 Answers2

1

For classes like these that have resources that need special handling after use, the AutoCloseable interface should be implemented. It gives the close() method which you can put the delete code in. It can then be used with the try with resources pattern like this:

try(YourClass yourObject = new YourClass()) {
    // do work with yourObject
}

The compiler will automatically put a finally block at the end and call yourObject.close(); within it to safely clean up resources.

Edit An example class would look like this:

class MyClass implements AutoCloseable {
    // create resources

    @Override
    public void close() throws Exception {
        // delete resources here
    }
}
Nathan Adams
  • 1,255
  • 1
  • 11
  • 17
  • really appreciated for your response but still not getting it in clear way, do in the way so we don't need to call finalize() into our class. Please if you show me some demo for above code it will be great :) – Hari Sheen May 02 '19 at 18:26
  • 1
    with AutoCloseable there's no need to have the delete code in finalize() too, so the method can be removed – Nathan Adams May 03 '19 at 11:33
1

It's understandable that there is resistance to your simply removing the finalize() method. After all, it's doing some useful cleanup. The question is what to replace it with.

Making the item AutoCloseable might help, though this only works if the item is used within a single lexical scope. This will enable you to use try-with-resources. If the item is not used within a lexical scope, for example, if it's plugged into several data structures, you can't really use try-with-resources. This is where you might need to perform some cleanup action after the item becomes unreachable.

The preferred replacement for finalization is to use something like a WeakReference. Normal references are "strong" references. When all strong references are gone, leaving only weak references, the item becomes "weakly reachable". This enqueues the reference on a reference queue; essentially this is an event that says "the item is no longer strongly reachable" and the action to be taken upon receiving this event is to perform some cleanup action.

This kind of reference processing can be inconvenient, so there is another mechanism called Cleaner that might be easier to use.

What made finalization convenient is that the finalize() method is on the about-to-be-collected object itself. Among the problems with finalization is that this "resurrects" the object by creating a new strong reference to it.

The trick with reference or Cleaner processing is that you need to keep track of stuff that needs to be cleaned up without keeping a reference to the object it's associated with. In your case you have a DiskCacheItem which is apparently held in a DiskCache. If a DiskCacheItem instance is about to be garbage collected, you want it removed from the DiskCache. It's hard to tell from your code, but it seems like the cleanup action is to remove a File object that might be associated with a DiskCacheItem. If so, here's what to do:

  1. Create a Cleaner instance that will be responsible for performing cleanup actions.

  2. Create a state class that contains the stuff to be cleaned up, in this case, a File.

  3. When a DiskCacheItem is added to the DiskCache, create an instance of the state class, and register it with the Cleaner, associating it with a cleanup action. In this case the cleanup action is to delete the file. This returns an instance of Cleanable.

  4. If there is an explicit "close" or "delete" action on DiskCacheItem, have it call clean() on the associated Cleanable object. This will invoke the cleanup action immediately.

  5. Sometime in the future, if the DiskCacheItem has not been deleted explicitly, and all strong references to it have been dropped, it will become phantom-reachable. This will cause the Cleaner to invoke the cleanup action.

This effectively replaces finalization and the finalize() method, though you will have to rearrange your data structures somewhat to do this.

After all this, what's the point of replacing finalization with the Cleaner/Cleanable mechanism? First, you can explicitly clean up a Cleanable. When it eventually becomes unreachable, it's just garbage collected. No extra processing is done. With finalization, even if a finalizable object has already been logically cleaned up, the JVM still needs to run the finalize() method. Second, finalization requires an extra GC pass to ensure that the object hasn't been "resurrected". With reference processing and Cleaner, there is no possibility of "resurrecting" an object. Third, finalization is fragile, and it's difficult to implement a finalize() method correctly.

Stuart Marks
  • 127,867
  • 37
  • 205
  • 259