The Final Word on “final”
In Java, overuse of final
feels like SHOUTING. It’s outdated and inappropriate much of the time.
Java and JavaScript
This is mainly about the final
keyword in Java, but my opinion on its counterpart const
in JavaScript has changed slightly. That I can think that const
is a good thing and final
is a bad thing needs some unpacking.
I like const
in JavaScript because, on the whole, code that uses let
or var
tends to do something I disagree with. On the whole, a variable should not need reassigning after it’s first given a value. That’s not true with accumulators, or certain looping situations, but it’s more true than it’s not.
Many refactorings I propose are of the formula stop reassigning that temporary variable and delegate to a function that chooses an answer and returns it.
So my premise is that code, largely, should work on the premise that all variables are to be treated as single-assignment by default.
Let’s Enforce It Then?
Why shouldn’t we enforce it in Java?
Java already has the concept of effectively final which brings the benefits of final to constructs which need to trust something is final – i.e. lambda functions and anonymous inner classes. Essentially the compiler already knows what’s final, and for me adding final
on top feels like shouting. It certainly makes the code busier… less is more, and final
feels like overcrowding.
I’ll forgive const
in JavaScript, partly because the linter is so keen to infer const
and then demand it, and partly because JavaScript is such a loose language, you can’t trust anything without expressing it firmly. That said, I’d rather not need it!
How Can We Trust Ourselves?
Yes, but how do I know something really is final
if I don’t say it’s final. What if someone changes it?
Example A:
1 2 3 4 5 6 7 8 | public bool isFound(List<String> list, String value) { for ( final String item:list) { if (value.equals(item)) { return true ; } } return false ; } |
The above code guarantees that item
inside the loop can’t be redefined. Number 1 – WHO CARES!? Number 2 – the method is very short. If a Ninja came up and tried to mutate the value of item
you’d notice it with short functions.
And that’s the point. If you have very short functions and keep your code modular, you can see what’s going on. You have no surprises and you can spot variables that change vs references that don’t.
Example B:
1 2 3 4 5 | final boolean hadValue = isFound(myList, "Foo" ); final boolean hadOtherValue = isFound(myList, "Bar" ); final boolean bothFound = hadValue && hadOtherValue; final String message = "They were both " + bothFound ? "found" : " not found" ; return message; |
Yawn!
1 2 | boolean bothFound = isFound(myList, "Foo" ) && isFound(myList, "Bar" ); return "They were both " + bothFound ? "found" : " not found" ; |
Don’t make me follow your thought process a word at a time with final
as the seasoning peppering the text. Make sentences of your code that explain whole thoughts and only add variables and modifiers if you need to.
Where Does Final Come In?
I use final
judiciously. I should say that I make all the child-services of my bean components/services in Spring private final
inside my classes, but I don’t. There’s an argument for it, namely that the wiring of the services inside an application context is innately immutable, but I tend not to. If you did, I’d not argue.
I have two key use cases where final
is a MUST!
They’re both about the importance of SHOUTING and Immutability.
- Global constants MUST be signposted as such
- Implementing the immutable pattern requires
final
and should also be signposted
So you’ll always find me using private static final SomeType SOME_CONSTANT_IN_CAPITALS
in class-level constants used within the class or as global variables, because they’re special and MUST be treated as constants with extra protection – the convention is strong and the danger of mistreatment much higher than a local variable in a single function.
You’ll find me wanting the immutable pattern implemented properly.
People who’ve studied for job interviews and know that final
also protects things from being overridden can feel smug at this stage until I say that I’m not really that interested in that usage of it. If you’re trying to prevent a programmer from having flexibility, or trying to satisfy checkstyle or Sonar by making something final
because it says so, then Meh!
But if you want truly immutable objects for some high cause, then I salute you.
Conclusion
When I start writing immutable data objects stored in caches and shared by multiple threads, you won’t be able to stop me from final
ing my way through it.
I’ll move your logger and your reference data into static final BLOCK_CAPITAL_NAME
d things every day of the week.
Most importantly, though: replace ALL “final ” with “” is still some of the most satisfying refactoring I’ve ever done.
Published on Java Code Geeks with permission by Ashley Frieze, partner at our JCG program. See the original article here: The Final Word on “final”
Opinions expressed by Java Code Geeks contributors are their own. |