Search code examples
javaeffective-java

Keeping a value class non-final for possible future extensibility


I am creating a very simple class called Catalog. It will be an immutable class and have an id and name field.

Out of habit, since I am not going to explicitly document this thing for extensibility, I put the final modifier on the class. However I'm wondering that since this is such a simple value class, would it hurt to leave the final modifier off in case someone in the future decides they could use it?


Solution

  • 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.)