42

Today I'm implementing a Closeable in kotlin, and as I have done in java in the past, I want to implement a finalize() as a last resort fallback in case the client code forgets to close it, rendering critical resource un-reclaimed. I consider this resource critical enough to add this fallback, despite the unreliability of this fallback. However, kotlin.Any does not declare a finalize method, which means I can't simplydo this:

class Resource: Closeable {
    fun close() {}
    override fun finalize() { close()}
}

This isn't good, at least not as good as it should be. Now I revert to plain Java as a workaround. Does anyone knows how to do this in pure Kotlin?

PS: My current workaround:

FinalizedCloseable.java:

public abstract class FinalizedCloseable implement Closeable {
    @Override protected void finalize() { close(); }
}

Kotlin:

class Resource: FinalizedCloseable(), Closeable {
    fun close() {}
    override fun finalize() { close()}
}

But this workaround requires a superclass. If next time my other Resource already got a superclass, this workaround won't work without a lot of boilerplate.


EDIT: Now I know how to implement finalize(), but IDEA kotlin plugin isn't smart enough to know that this is a finalizer and thus mark it with some warning. After struggling for a while I found how to suppress these warnings, and I want to share it:

class C {
    @Suppress("ProtectedInFinal", "Unused") protected fun finalize() {}
}
glee8e
  • 6,180
  • 4
  • 31
  • 51
  • 1
    https://kotlinlang.org/docs/reference/java-interop.html#finalize – ean5533 May 04 '17 at 13:26
  • @ean5533 Uh I didn't read that long interop doc completely, and now is my punishment. Thank you anyway. – glee8e May 04 '17 at 13:28
  • Have you read “[finalize() called on strongly reachable object in Java 8](https://stackoverflow.com/q/26642153/2711488)”? The bottom line is, you should better not do that at all. Unless your code involves `native` code dealing with a system resource directly, your class will be a wrapper around another object actually representing the resource and letting the reachability of the wrapper determine the life time of the actual resource (which might still be reachable and in use), means asking for serious problems… – Holger May 04 '17 at 13:39
  • @Holger Thank you for pointing that out. But my problem is that only part of the resource is consumed by one handler, and the rest of them will be stored in a pool until other handler, or even the failing handler, pulled again. Thus occasionally failing once is not a concern in my software. However, I don't want to risk losing any of them, or there will be an army of 300 ramming my front door. BTW, on my machine the `FinalizeThis::finalize` in the example in your link is *never called even once* on my machine. – glee8e May 04 '17 at 13:58
  • It’s all JVM specific. Beside the danger of being called too early, there is a huge probability of being never executed at all, at least, not within the critical time frame. Garbage collection is meant to manage memory and as long as there’s enough memory or the garbage collector is happy with reclaiming the storage of objects not needing finalization, it might not run or just ignore the object with finalizers. And there’s the multi-threading issue… – Holger May 04 '17 at 14:06

1 Answers1

69

The official documentation covers this.

To override finalize(), all you need to do is simply declare it, without using the override keyword:

class C {
    protected fun finalize() {
        // finalization logic
    }
}
zsmb13
  • 85,752
  • 11
  • 221
  • 226
  • 1
    Beat me to it by seconds :) – ean5533 May 04 '17 at 13:27
  • Thank you! That's all I need! But why stackoverflow prohibit selecting the anwser before 12 minutes have pasted... – glee8e May 04 '17 at 13:30
  • 2
    Ok, it works, but how to call `super.finilize()` in it? I decompiled generated java code and there is no super call there. – don11995 May 10 '18 at 09:10
  • @don11995 Would that actually be an issue, as Object.finalize doesn't do anything? – Boris Jun 06 '18 at 11:23
  • 2
    @Boris Yes, in the case that you extend a class that has code for it. But, there is no need for it when none of the class you extend from have it overridden. But if the class you extend from allows it, you should be able to call `super.finalize` and all works fine anyway. – android developer Jul 18 '18 at 12:31
  • 1
    But does it work? Will this function run when the object is prepared to be freed? – Aaron Lee Jul 26 '19 at 06:48
  • 1
    @AaronLee Yes, it does work. It's a bit odd looking, but it will indeed be called when the object is being freed. – Trevor Jun 21 '21 at 19:53
  • I can confirm the the function is called. – Luis Aug 09 '23 at 19:13