Java – Object oriented immutability: final classes or final methods

javaobject-oriented

One of the things you see in numerous places in the standard java library is final classes. It is claimed that this is for immutability which I understand…to an extent.

Suppose you have a class:

final public class ImmutableTest {
    private String value;
    public ImmutableTest(String value) {
        this.value = value;
    }
    public String getValue() {
        return this.value;
    }
}

You can say that the value is immutable because it can't be adapted after creation. However this limits usability of the class as no one can extend it (for example to use as a drop-in for a bad interfaceless design…).

Now suppose you have this class:

public class ImmutableTest {
    private String value;
    public ImmutableTest(String value) {
        this.value = value;
    }
    final public String getValue() {
        return this.value;
    }
}

The "value" is still immutable but now at least people can extend the class. Someone once interjected: but if you extend it, the extended class is not guaranteed to be immutable!

While this is true, I think it is immaterial to the class itself.

If user A uses my ImmutableTest class everywhere in his code, he only has access to the "value" anyway which remains immutable. Unless he does explicit casting (in other words: he's aware that he's trying to access other stuff) he can't access a "mutable" part of the actual instance which means from the developer's point of view the class is as immutable as it should be, even if the actual instance has other mutable variables.

So in short: my opinion is that final classes are superfluous as final methods are all you need. I would love to hear arguments to the contrary though!

UPDATE

To clarify: I'm not claiming that adding "final" to a class or its methods makes it immutable.

Suppose you have a class that is designed to be immutable but you do not make the methods or class final, a subclass can of course make it mutable again. This argument is used as to why some classes in the standard library are final. My opinion is that it should've been enough to finalize the accessor methods to the immutable part and leave the class non-final.

This may leave the window open to the child objects adding mutable fields but the original set of fields would remain immutable hence satisfying the "immutable" requirement for the initial set of methods.

UPDATE2

The conclusion being that final classes have no real purpose except perhaps brevity which in itself is not enough of a reason to lose extensibility in my opinion.

Best Answer

Declaring immutable class final saves programmer from the need to repeat declaring final in each and every method declaration, over and over and over again.

In classes like java.lang.String, having over 60 methods, this is substantial save, as well as important guarantee that necessary modifier won't be omitted by mistake.

When object is intended to be immutable, mistakes to declare final method may be hard to detect, because there is no reliable way to tell whether programmer omitted final modifier intentionally or by mistake.

final classes have no real purpose except perhaps brevity

Besides brevity and helping to avoid mistakes, a strong benefit of declaring immutable class final is that this makes programmer's intent explicit, unambiguously communicating to API users that none of class methods are intended for override.

Alternative way, that is, declaring all methods final, lacks this important "feature", as it leaves users of the API in the indecisive state, whether API designers intended to only protect some methods from overloading, and it only accidentally turned out that all of them got final, or there was a design decision to cover all the class.

my opinion is that final classes are superfluous as final methods are all you need

Given above, having final modifier for class doesn't look superfluous to me.

It is worth noting that Sun/Oracle Java tutorial presents final classes as a matter of usefulness and not as that of convenience. If final classes purpose was mere brevity / syntactic sugar, one would expect tutorial to explain these as convenience.

...you can also declare an entire class final. A class that is declared final cannot be subclassed. This is particularly useful, for example, when creating an immutable class like the String class.

Related Topic