17

I like my code to be written well; however, I have run into not really an problem, but more of a question about conventions. Say I have this class.

public class Test {

    public void doStuff() {
        System.out.println("stuff");
    }
}

This class is not going to be extended, so should it be final? I know that when you don't want a class to be extended you make it final; however, in this case the class isn't going to be extended. Sorry if that is confusing. I am basically wondering if you should make every class that isn't going to be extended final.

2 Answers2

13

One of the rules for checkstyle that I have a love/hate relationship with is in the Class Design section - Design For Extension. I've often found myself turning it off because it is annoying to follow to a 'T' - especially on large legacy projects where it isn't followed (having a bajillion warnings from check style makes it harder to fix any of them).

That said, its a rather simple rule:

The exact rule is that nonprivate, nonstatic methods of classes that can be subclassed must

  • be abstract or
  • be final or
  • have an empty implementation.

If you can subclass a class, you should make it so that it can be extended in a meaningful way.

"Wait," you say, "This is rule is about public non-static methods that either must be abstract, final, or have an empty implementation. What does this have to do with a final class?"

The exact rule is that non private, non static methods of classes that can be subclassed must ...

If you leave a class non-final, you are saying that it can be subclassed in a meaningful way. If it can't, then it shouldn't be able to be subclassed.

By making a class final, you are making it just a little bit harder for your co-worker to tinker with its innards by making a subclass that exposes all the methods that are implementation specific. There are few things as wonderful as tracking down a bug because an immutable you wrote was subclassed to become mutable - trust me on this.

Designing for inheritance is costly. It takes extra thought to make sure that you are doing it right. That someone else won't mess it up. By saying final class you are avoiding all of that and saying "no - this cannot be inherited" and making it that much easier to reason about.

If you are not spending the time to design the class for extensibility, the appropriate thing to do is make sure no one makes the mistake working from the belief that the class is extensible.

Related reading:

11

Eric Lippert has an excellent blog post on why one would mark classes final. Specifically, he refers to the Microsoft practice of declaring .NET Framework classes sealed, but the principles are the same.

To summarize, writing an extensible class is a whole different ball game than writing a final class.

  • Sealing classes means you don't have to think about the myriad ways that a consumer might break the class by extending it.

  • Writing extensible classes requires a more rigorous design process. You have to design them to be easily, clearly and logically extensible, a design consideration that you don't have to think about at all if you simply seal the class.

  • You lose encapsulation when you allow a class to be inherited.

  • Supporting an extensible class is much more involved. Yes, you have to support the many ways a consumer might extend it. If you upgrade the class later, you have to worry about breaking consumers' extensions.

See Also
Why aren't classes sealed by default?

Glorfindel
  • 3,167
Robert Harvey
  • 200,592