Martin Fowler compared Designed Inheritance to Open Inheritance
. With Designed Inheritance, you either allow and design for class extension or prohibit it. Open Inheritance on the other hand leaves everything open to extension.
Martin focused on Designed Inheritance protecting users from sharp knives, but compatibility is the real issue at stake. Experts vs. non experts aside, Designed Inheritance helps API designers keep their promises.
If I modify a non final class in my library, I have to anticipate every possible way existing users may have already extended my class and ensure my change doesn't alter the behavior of their code. In the case of a widely used API like the JDK, you simply can't make a change if the remotest possibility of breaking someone exists, even if you're fixing a bug. When it comes to using the JDK, if someone can, someone did. You need a compelling reason to force users to modify and recompile working code.
Which approach is best? Neither. As with most design debates, it depends.
If you write a library where you don't have control over client code and you need to maintain compatibility, steer clear of unnecessary maintenance headaches and practice Designed Inheritance. Use interfaces generously so users don't need to extend your classes in the first place. If you allow users to extend a class, don't call non final methods from your constructor--you risk calling user code before their constructor executes. Many of the idioms in Effective Java target this audience.
If you're writing internal or application code, don't waste too much time defending against yourself and don't over design. Strike a balance between effort and usability and maintainability. Leave your classes open; don't bother with too many interfaces. You can always refactor later.
And don't bother taking sides.