loading...

Effective Java Tuesday! Avoid Finalizers and Cleaners!

kylec32 profile image Kyle Carter ・3 min read

Effective Java Review (36 Part Series)

1) Effective Java Tuesday! Let's Consider Static Factory Methods 2) Effective Java Tuesday! The Builder Pattern! 3 ... 34 3) Effective Java Tuesday! Singletons! 4) Effective Java Tuesday! Utility Classes! 5) Effective Java Tuesday! Prefer Dependency Injection! 6) Effective Java Tuesday! Avoid Creating Unnecessary Objects! 7) Effective Java Tuesday! Don't Leak Object References! 8) Effective Java Tuesday! Avoid Finalizers and Cleaners! 9) Effective Java Tuesday! Prefer try-with-resources 10) Effective Java Tuesday! Obey the `equals` contract 11) Effective Java Tuesday! Obey the `hashCode` contract 12) Effective Java Tuesday! Override `toString` 13) Effective Java Tuesday! Override `clone` judiciously 14) Effective Java Tuesday! Consider Implementing `Comparable` 15) Effective Java Tuesday! Minimize the Accessibility of Classes and Member 16) Effective Java Tuesday! In Public Classes, Use Accessors, Not Public Fields 17) Effective Java Tuesday! Minimize Mutability 18) Effective Java Tuesday! Favor Composition Over Inheritance 19) Effective Java Tuesday! Design and Document Classes for Inheritance or Else Prohibit It. 20) Effective Java Tuesday! Prefer Interfaces to Abstract Classes 21) Effective Java! Design Interfaces for Posterity 22) Effective Java! Use Interfaces Only to Define Types 23) Effective Java! Prefer Class Hierarchies to Tagged Classes 24) Effective Java! Favor Static Members Classes over Non-Static 25) Effective Java! Limit Source Files to a Single Top-Level Class 26) Effective Java! Don't Use Raw Types 27) Effective Java! Elminate Unchecked Warnings 28) Effective Java! Prefer Lists to Array 29) Effective Java! Favor Generic Types 30) Effective Java! Favor Generic Methods 31) Effective Java! Use Bounded Wildcards to Increase API Flexibility 32) Effective Java! Combine Generics and Varargs Judiciously 33) Effective Java! Consider Typesafe Hetergenous Containers 34) Effective Java! Use Enums Instead of int Constants 35) Effective Java! Use Instance Fields Instead of Ordinals 36) Effective Java! Use EnumSet Instead of Bit Fields

Here we are at the eighth chapter of Effective Java and it's another more niche topic. Today we are talking about finalizers and cleaners. Huh? What are those? The author of Effective Java just kind of jumps into why not to use them and doesn't really explain what they are there for (maybe because he doesn't want to entice you to use them). Anyway, I figured it would be good to actually start with what they are before we dig into why we shouldn't use them because when I first read about them I had never heard of or used them.

The two concepts basically do the same thing but in two different ways. Finalizers are the elder of the two options and is a core part of the Java language. It is a method on the class Object that can be overridden. So what does it do. Simply a finalizer is a method that gets called right before a object is removed by the garbage collector. This function can be used for many purposes including bringing the object back to life (why? 🤷) but most commonly used to clean up resources for an object. Cleaners are more or less the same type of thing (but not part of the class Object) but for a post Java 9 world where finalizers were deprecated and help overcome some of the shortcomings. They however still should be avoided.

OK, now that we know what they do and how they can be useful let's ruin it by saying all the reasons we shouldn't use them.

The Time When the Finalizer Is Indeterminate
Because we don't have control over when the garbage collector runs we also cannot be sure when the finalizer will run. Because of this we shouldn't count on it cleaning up finite resources like file handles for us as it may not be able to do it in time. While we likely will get some consistency of behavior if we test on the same JVM we deploy on but there will still be plenty of variability. If we deploy on different JVMs this becomes even more wide open to different behaviors. We also run the risk of the finalizer thread being run at a lower priority than the rest of the threads in the system and thus no being able to keep up with the creation of objects.

The Finalizer May Never Be Called
So what is worse than not being able to determine when the finalizer will run is realizing that the finalizer may never run. That's right, according to the specification a finalizer may never be called. This should make it apparent that these should not be used to clean up persistent state. There are methods that can increase your odds of the finalizer being called (System.gc and System.runFinalization) but these still don't guarantee the finalizer will be called.

Exceptions Thrown In A Finalizer Are Ignored
Of note, cleaners don't have this problem but whenever we have an exception that is simply swallowed and stopping the garbage collection is something we want to avoid.

Finalizers Come With a Severe Performance Cost
Because finalizers and cleaners get in the way of efficient garbage collection algorithms it can slow thing down by quite a bit. In the author's experiment he saw a 50x decrease in performance when using a finalizer. Everyone loves good performance so this is not something we want.

OK, so we have gone over all the horrible things about them. When could these still be useful. First, because they are deprecated, there really is no need for finalizers in modern Java applications. So that leaves cleaners, when should we use them? Effective Java brings up two potential use cases. One was to act as a safety net for regular clean up. While it shouldn't be the main way of cleaning up items it can serve as a safety net for when developers forget to manually manage their resources. The second use case would be using it when we have native components that our Java code is managing. Of course the garbage collector can't manage these native components and therefore we do have to manage it more ourselves.

Finally, we have gone over what not to do, what should we do instead? The need to clean up resources is a real one that still needs to be accounted for. The solution is quite simple. Simply have your class implement AutoCloseable and implement the close method to clean up the resources we may have created in the life of the object. This puts management in our hands. We will be talking more about this next week in our next episode.

So there we have it. Finalizers and cleaners. Have you ever used these? Have you had any luck? Share in the comments.

Effective Java Review (36 Part Series)

1) Effective Java Tuesday! Let's Consider Static Factory Methods 2) Effective Java Tuesday! The Builder Pattern! 3 ... 34 3) Effective Java Tuesday! Singletons! 4) Effective Java Tuesday! Utility Classes! 5) Effective Java Tuesday! Prefer Dependency Injection! 6) Effective Java Tuesday! Avoid Creating Unnecessary Objects! 7) Effective Java Tuesday! Don't Leak Object References! 8) Effective Java Tuesday! Avoid Finalizers and Cleaners! 9) Effective Java Tuesday! Prefer try-with-resources 10) Effective Java Tuesday! Obey the `equals` contract 11) Effective Java Tuesday! Obey the `hashCode` contract 12) Effective Java Tuesday! Override `toString` 13) Effective Java Tuesday! Override `clone` judiciously 14) Effective Java Tuesday! Consider Implementing `Comparable` 15) Effective Java Tuesday! Minimize the Accessibility of Classes and Member 16) Effective Java Tuesday! In Public Classes, Use Accessors, Not Public Fields 17) Effective Java Tuesday! Minimize Mutability 18) Effective Java Tuesday! Favor Composition Over Inheritance 19) Effective Java Tuesday! Design and Document Classes for Inheritance or Else Prohibit It. 20) Effective Java Tuesday! Prefer Interfaces to Abstract Classes 21) Effective Java! Design Interfaces for Posterity 22) Effective Java! Use Interfaces Only to Define Types 23) Effective Java! Prefer Class Hierarchies to Tagged Classes 24) Effective Java! Favor Static Members Classes over Non-Static 25) Effective Java! Limit Source Files to a Single Top-Level Class 26) Effective Java! Don't Use Raw Types 27) Effective Java! Elminate Unchecked Warnings 28) Effective Java! Prefer Lists to Array 29) Effective Java! Favor Generic Types 30) Effective Java! Favor Generic Methods 31) Effective Java! Use Bounded Wildcards to Increase API Flexibility 32) Effective Java! Combine Generics and Varargs Judiciously 33) Effective Java! Consider Typesafe Hetergenous Containers 34) Effective Java! Use Enums Instead of int Constants 35) Effective Java! Use Instance Fields Instead of Ordinals 36) Effective Java! Use EnumSet Instead of Bit Fields

Posted on by:

kylec32 profile

Kyle Carter

@kylec32

Backend Architect at MasterControl

Discussion

markdown guide