Pun intended… Let’s discuss Java final
.
Recently, our popular blog post “10 Subtle Best Practices when Coding Java” had a significant revival and a new set of comments as it was summarised and linked from JavaWorld. In particular, the JavaWorld editors challenged our opinion about the Java keyword “final
“:
More controversially, Eder takes on the question of whether it’s ever safe to make methods final by default:
“If you’re in full control of all source code, there’s absolutely nothing wrong with making methods final by default, because:”
- “If you do need to override a method (do you really?), you can still remove the final keyword”
- “You will never accidentally override any method anymore”
Yes, indeed. All classes, methods, fields and local variables should be final by default and mutable via keyword.
Here are fields and local variables:
int finalInt = 1; val int finalInt = 2; var int mutableInt = 3;
Whether the Scala/C#-style val
keyword is really necessary is debatable. But clearly, in order to modify a field / variable ever again, we should have a keyword explicitly allowing for it. The same for methods – and I’m using Java 8’s default
keyword for improved consistency and regularity:
class FinalClass { void finalMethod() {} } default class ExtendableClass { void finalMethod () {} default void overridableMethod() {} }
That would be the perfect world in our opinion, but Java goes the other way round making default
(overridable, mutable) the default and final
(non-overridable, immutable) the explicit option.
Fair enough, we’ll live with that
… and as API designers (from the jOOQ API, of course), we’ll just happily put final
all over the place to at least pretend that Java had the more sensible defaults mentioned above.
But many people disagree with this assessment, mostly for the same reason:
As someone who works mostly in osgi environments, I could not agree more, but can you guarantee that another api designer felt the same way? I think it’s better to preempt the mistakes of api designers rather than preempt the mistakes of users by putting limits on what they can extend by default. – eliasv on reddit
Or…
Strongly disagree. I would much rather ban final and private from public libraries. Such a pain when I really need to extend something and it cannot be done.
Intentionally locking the code can mean two things, it either sucks, or it is perfect. But if it is perfect, then nobody needs to extend it, so why do you care about that.
Of course there exists valid reasons to use final, but fear of breaking someone with a new version of a library is not one of them. – meotau on reddit
Or also…
I know we’ve had a very useful conversation about this already, but just to remind other folks on this thread: much of the debate around ‘final’ depends on the context: is this a public API, or is this internal code? In the former context, I agree there are some good arguments for final. In the latter case, final is almost always a BAD idea. – Charles Roth on our blog
All of these arguments tend to go into one direction: “We’re working on crappy code so we need at least some workaround to ease the pain.”
But why not think about it this way:
The API designers that all of the above people have in mind will create precisely that horrible API that you’d like to patch through extension. Coincidentally, the same API designer will not reflect on the usefulness and communicativeness of the keyword final
, and thus will never use it, unless required by the Java language. Win-win (albeit crappy API, shaky workarounds and patches).
The API designers that want to use final for their API will reflect a lot on how to properly design APIs (and well-defined extension points / SPIs), such that you will never worry about something being final
. Again, win-win (and an awesome API).
Plus, in the latter case, the odd hacker will be kept from hacking and breaking your API in a way that will only lead to pain and suffering, but that’s not really a loss.
Final interface methods
For the aforementioned reasons, I still deeply regret that final
is not possible in Java 8 interfaces. Brian Goetz has given an excellent explanation why this has been decideed upon like that. In fact, the usual explanation. The one about this not being the main design goal for the change ;-)
But think about the consistency, the regularity of the language if we had:
default interface ImplementableInterface { void abstractMethod () ; void finalMethod () {} default void overridableMethod() {} }
(Ducks and runs…)
Or, more realistically with our status quo of defaulting to default
:
interface ImplementableInterface { void abstractMethod () ; final void finalMethod () {} void overridableMethod() {} }
Finally
So again, what are your (final) thoughts on this discussion?
If you haven’t heard enough, consider also reading this excellent post by Dr. David Pearce, author of the whiley programming language
Filed under: java Tagged: API design, final, final keyword, java, keywords
