final means, this value won’t be changed
hereafter.
Advantages of using final
final is one of the most under-used features of Java.
Whenever you compute a value and you know it will never be changed subsequently put
a
final on it. Why?
- final lets other programmers (or you reviewing
your code years later) know they don’t have to worry about the value being
changed anywhere else.
- If you get in the habit of always using final,
when it is missing, it warns people reading your code there is a redefinition of
the value elsewhere.
- final won’t let you or someone else
inadvertently change the value somewhere else in the code, often by setting it to
null. final helps
prevent or flush out bugs. It can sometimes catch an error where an expression is
assigned to the wrong variable. You can always remove it later.
- final helps the compiler generate faster code,
though I suspect a clever compiler could deducing finality, even when the
final is missing. final
values can sometimes be in-lined as literals. They can be further collapsed at
compile time in other final expressions.
- I have got into the habit of using final
everywhere, even on local variables and if I am in doubt, I use final on every declaration then take it off when the compiler
points out that I modified it elsewhere. When I read my own code, a missing
final is a red flag there is something complicated
going on to compute a value.
- A little known feature of Java is blank finals. You
can declare member variables final, but not declare
a value. This forces all constructors to initialise the blank final variables. A final idiom
- If you reference a static final in another
class, that value often becomes part of your class at compile time. The source
class then need not be loaded to get the value and the source class need not
even be included in the jar. This helps conserve RAM (Random Access Memory)
and keep your jars small.
- At the machine language level, static finals can
be implemented with inline literals, the most efficient form of addressing
data.
If I were redesigning Java, I would make all variables final by default. This
would reduce the visual clutter and make the rarer var
variables stand out.
Implied Final
In Java 1.8, the compiler sometimes does not insist you use final, just that you could.
This implied final was introduced to make lambdas terser. As a side effect you can access implied final
variables in your anonymous classes.
final contexts
The term final is used in a number
of contexts. static final variables are close to
constants in other languages. final classes may not be
subclassed. final methods may not be overridden. On
methods private implies final, but on variables does not. Marking things final has two purposes: efficiency and safety. The compiler can
perform various optimisations knowing the value cannot change. Hotspot and optimising
compilers now do this anyway, whether or not you declare methods final, so using final purely for
efficiency is no longer recommended. The compiler can also check to ensure you do not
inadvertently attempt to change the value after computing its value once where it is
defined.
You can have both final instance and final static variables. final statics
are more common. When you know the value of a constant at compile time you might as
well make it static. It takes up less room, just one
copy per class instead of one copy per object. It is also faster to access a static
constant than an instance constant. However, if you don’t know the value of the
constant until instantiation time, you
have to make it an instance constant.
final is not the same as C++ const
If you
have a final reference to an object or array, it does
not stop you from changing the fields in the object or elements of
the array. final just stops you from pointing that
reference variable to a different object or array. If you want to protect the object
from changes, you must make it immutable, namely remove any
setter methods from its class definition. Java’s final is not as flexible and powerful as C++ const, however, Java’s
final is less error prone.
My Philosophy
I use IntelliJ
IDE. It strenuously urges you to mark final any
class that is not currently overridden. This helps document which
classes currently have overrides and which don’t. final also helps the compilers, JITs (Just In Times)
and AOTs (Ahead Of Times) to
generate faster code. Since I always distribute source code, I figure you can easily
remove the finals wherever they get in the way of your
own overriding and extending. If I were distributing only class files, I would have
to be much more careful about finals, since final prevents you from extending that class or method.
The problem is, when I release updated source, you have to re-remove the
finals to make your code work.
Learning More
If you are a language
lawyer, you might enjoy digging into the JLS (Java Language Specification)
for its academic descriptions on how final is used.