In my opinion, it is good practice to make simple value types final
. If you want to guarantee immutability, you actually have to do so. That's also (partially) why String
, Integer
, etc are all final
.
If your class is not final
, somebody could extend it by adding methods that mutate it. A client who is passed an instance of the extended type (upcasted to your type) would falsely believe to deal with an immutable object when it actually isn't.
In my own code, I actually go a little further and make almost any class final
if I didn't design it with extensibility explicitly in mind. If you want to support extension, consider providing an abstract class or an interface. This is also in line with the abstract, final or empty rule for methods.
Update: Why does immutability require a class to be final
? Of course, there are other ways to ensure a particular attribute of an object is not changed.
Consider for example a RGBColor
class with three attributes red
, green
and blue
of type byte
. We make all three final
and set them in the constructor once for all time. (We can additionally make them private
and add appropriate getter methods but that's not important for the sake of this discussion.) Of course, we override the equals
method to return true
if and only if the compared object is an instance of RGBColor
with the same red
, green
and blue
values.
This looks innocent but what if somebody decides to extend our class to a RGBAColor
class by adding an alpha
attribute? Naturally, the extender would desire to override equals
to also take into account the alpha
value. Suppose our extender also isn't very careful about immutability and thus makes alpha
non-final
and supplies a setter for it.
Now, if we are given an object of type RGBColor
, we cannot safely assume that if it compared equal to another one, it will still do so a minute from now. We could have prevented this (particular problem) by also declaring equals
as final
in our RGBColor
class. But then, we could have equally well made the entire class final
because extending a value type without the possibility to extend the notion of equality is close to useless. (Thre are other problems with overriding equals
such as it not being symmetric. I generally feel not too comfortable about it.)