Finalizers are a way to have a chunk of code executed when an object is garbage collected.
Pros: can be handy for doing cleanup, particularly of external resources.
Cons: there are no guarantees as to when a finalizer will be called, or even that it will be called at all.
Decision: we don’t use finalizers. In most cases, you can do what you need from a finalizer with good exception handling. If you absolutely need it, define a close() method (or the like) and document exactly when that method needs to be called. See InputStream for an example. In this case it is appropriate but not required to print a short log message from the finalizer, as long as it is not expected to flood the logs.