final
keyword liberally to communicate your intent.
The final
keyword has more than one meaning:
final
class cannot be extendedfinal
method cannot be overriddenfinal
fields, parameters, and local variables cannot change their
value once setfinal
object reference is set, it can still
change its state, but not its identity (that is, you can't re-point the object reference to
some other object).
Declaring primitive fields as final
automatically ensures thread-safety
for that field.
Some habitually declare parameters as final
, since this is almost
always the desired behaviour. Others find this verbose, and of little real benefit.
Consistently using final
with local variables (when appropriate)
can be useful as well. It brings attention to the non-final
local
variables, which usually have more logic associated with them (for example,
result
variables, accumulators, loop variables). Many find this verbose.
A reasonable approach is to occasionally use final
for local variables,
but only if there is some unusual condition, whereby making final
explicit can call
attention to at least one non-final
local variable in the method; this serves
to quickly distinguish the non-final
local variables from the others.
Using final
:
final
says,
"If you are looking for complexity, you won't find it here."import java.util.*; /** This class cannot be extended, since it's final. */ public final class Boat { public Boat(final String name, final int length, final Date dateManufactured){ this.name = name; this.length = length; //make a defensive copy of the date this.dateManufactured = new Date(dateManufactured.getTime()); //does not compile, since the items are final: //aDateManufactured = null; //aLength = 0; } /** Cannot be overridden, since the class itself is final. */ public void setDate(final Date newDate){ //even though the field is final, its state can change: dateManufactured.setTime(newDate.getTime()); //does not compile, since field is final: //fDateManufactured = aNewDate; } /** Return the highest race score. */ public Integer bestRaceScore(){ //the result reference can't be final, since it can be //re-pointed to different objects Integer result = Integer.valueOf(0); //final Integer result = Integer.valueOf(0); //doesn't compile //this example is artificial, since raceScores could be //referenced directly here... final List<Integer> scores = raceScores; for(Integer score : scores){ if (score > result){ result = score; //re-point to the max value } } return result; } //..elided // PRIVATE private final String name; private final int length; private List<Integer> raceScores = new ArrayList<>(); /** New code should almost always use java.time, not java.util.Date. java.util.Date is used here simply as an example of a mutable field. */ private final Date dateManufactured; }