One of the interesting differences between .NET and Java I ran into while reading Joshua Bloch’s excellent “Effective Java” book is the handling of finalizers.
In both, .NET and Java, the Garbage Collector will implicitly place objects implementing a finalizer and are eligible for collection on a finalizer queue. This queue is processed by a separate finalizer thread, and no guarantees are made as to when an object may be finalized or if it will be finalized at all. The reason finalization cannot be guaranteed is that the process may crash, finalization throws an exception or similar mishappenings.
Due to the nature of the finalization, it comes with significant overhead. To avoid this overhead, .NET provides the IDisposable pattern. The
Dispose method takes care of releasing all allocated resources and then instructs the Garbage Collector with a call to
GC.SupressFinalizer(this) that it need not be finalized anymore.
Clients of objects implementing
IDisposable are responsible (though not forced to) call
IDisposable.Dispose whenever they are done with an instance. To support this scenarios, many .NET languages feature a
using keyword, which is syntactic sugar for providing a scope for disposable objects. Whenever this scope is left, the appropriate
Dispose method is called.
Java on the other does not provide a general purpose equivalent to
IDisposable, for IO related the
Closeable interface exists. As of Java 6 there is no equivalent to the using keyword, although “Automatic Resource Block Management” using the
try keyword has been announced for Java 7. Until then, you’re left with manually implementing scoping with a
try/finally block. Java also doesn’t provide an equivalent of
GC.SupressFinalize which means that finalizable objects will always have significant performance impacts.
A further difference is in the way base class finalization is handled. Although the .NET CLI Spec does not enforce base class finalizers are called from a derived class’ finalizer, C# and C++/CLI enforce this with their destructor syntax. In Java, it is up to the implementor not to forget calling the base class finalizer.
All these aspects, combined with the significantly better support for code issue warnings around undisposed Disposables in the .NET stack, make .NET’s handling look superior to Java’s.