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.