The Final Word On the final Keyword
Some features of the Java language simply cannot be ignored.
Consider for example interfaces, used extensively by every Java specification;
try/catch blocks, that form the basis for exception handling.
Other features are more obscure – useful, but ignored by the masses.
Without looking as far as
volatile (probably the most obscure Java keyword),
final. When was the last time you used
final in your code?
Me, I'm a
final fan. Enamored with
final, I'm of
the school of thought that inserts
final any where, any time.
Or almost. But why?
In this article I shine the spotlight on the Java keyword
invite you to discover its subtle meanings, and the many Java idioms that make use of it. All for
- The Many Meanings of
- Final Variables
- Final Parameters
- Anonymous Local Classes
- Final Fields
- Declare Constants
- Aggregation vs. Acquaintance
- Enforce Atomicity of Object Creation
- Declare Invariants
- For Performance
- Conclusion on Final Fields
- Final Methods
- Enforce Invariant Code
- For Security
- For Performance?
- Final Classes
- Enforce Composition over Inheritance
- For Security
- Immutable Objects
The Many Meanings of
final modifier can be applied to four Java constructs:
- variables: a final variable can be set once and only once.
- fields: a final field can also be set only once, by the constructor
of the class which defines it.
- methods: a final method cannot be overridden nor hidden.
- classes: a final class cannot be extended.
Notice how using
final is an entirely negative act.
final keyword works by subtracting, limiting default language mechanisms:
the ability to override a method, to set a variable or a field.
The motivations behind
final fall into three broad categories: correctness,
robustness, and finally performance.
A final variable can be set only once, allowing you to declare
local constants. Such a variable can be left un-assigned at the point of declaration,
creating blank finals. But all final variables must be assigned exactly
Final variables come in handy in mostly two situations: to prevent accidental
changes to method parameters, and with variables accessed by anonymous classes.
The following sample declares final parameters:
public void doSomething(final int i, final int j)
final is used here to ensure the two indexes
won't accidentally be reset by the method.
It's a handy way to protect against an insidious bug
that erroneously changes the value of your parameters. Generally speaking,
short methods are a better way to protect from this class of errors,
but final parameters can be a useful addition to your coding
Note that final parameters are not considered part of the method signature,
and are ignored by the compiler when resolving method calls. Parameters can be
declared final (or not) with no influence on how the method is overriden.
Anonymous Local Classes
The second situation involving final variables
is actually mandated
by language semantics. In that situation, the Java compiler won't let you use a variable
unless it is declared final.
This situation arises with closures, also known as anonymous local classes.
Local classes can only reference local variables and parameters that are
public void doSomething(int i, int j)
final int n = i + j; // must be declared final
Comparator comp = new Comparator()
public int compare(Object left, Object right)
return n; // return copy of a local variable
The reason for this restriction becomes apparent if we shed
some light on how local classes are implemented.
An anonymous local class can use local variables because the compiler automatically gives
the class a private instance field to hold a copy of each local
variable the class uses. The compiler also adds hidden parameters to each
constructor to initialize these automatically created
private fields. Thus, a local class does not actually access
local variables, but merely its own private copies of them. The only way
this can work correctly is if the local variables are declared final,
so that they are guaranteed not to change. With this guarantee in place, the local
class is assured that its internal copies of the variables accurately reflect
the actual local variables.
A final field can be assigned once and only once, and must be initialized
by every constructor of the class that declares it.
It is also possible to assign the field directly, in the same statement
where it is defined. This simply reflects the fact that such shortcut
assignments are compiled into a synthetic constructor.
E.g. both the following code samples are correct and strictly equivalent;
the first is preferred for being shorter.
public class MyClass
private final int i = 2;
public class MyClass
private final int i;
i = 2;
final is used to flag constants. This usage
is well-known to all Java programmers, so I won't expand much on it.
It is useful to know that the value of a field declared constant in that manner
will be computed statically if possible, at compile-time.
private static final int ERROR_CODE = 1 + 3 * 4 / 2;
public static final String ERROR_MESSAGE = "An error occurred with code=" + ERROR_CODE;
The compiler will compute the value for
concatenate the string equivalent
of the result, and assign the resulting
Aggregation vs. Acquaintance
In the words of Gamma et al.'s Design Patterns:
Aggregation implies that one object owns or is responsible for another object.
Generally we speak of an object having or
being part of another object.
Aggregation implies that an aggregate object and its owner have identical
Acquaintance implies that an object merely knows of another object. Sometimes
acquaintance is called "association" or the "using" relationship. Acquainted
objects may request operations of each other, but they aren't responsible for
each other. Acquaintance is a weaker relationship than aggregation and suggests
much looser coupling between objects.
It's easy to confuse aggregation and acquaintance, because they are often
implemented in the same way. Ultimately, acquaintance and aggregation are
determined more by intent than by explicit language mechanisms.
Aggregation relationships tend to be fewer and more permanent than acquaintance.
Acquaintance, in contrast, are made and remade more frequently, sometimes
existing only for the duration of an operation. Acquaintances are more dynamic
as well, making them more difficult to discern in the source code.
As it turns out, the Java language does offer an explicit mechanism to differentiate
aggregation relationships from mere acquaitances: the object of this article,
Use it to flag and make explicit aggregations.
But why should this be important to you? The short answer is:
to improve code quality.
Enforce Atomicity of Object Creation
Once a field is determined to be an aggregation of another object,
and it is declared final, an interesting property emerges.
The aggregating object is guaranteed to be created in full,
or it won't be created at all; either all final fields are initialized
successfully, or an exception terminates the constructor.
Say an object Car aggregates another object Engine, and therefore is defined as
an Engine instance to function. Declaring the reference to the Engine as final
ensures any Car instance is correctly initialized in full
– or the constructor was terminated abruptly by a thrown exception.
The Car class doesn't even compile without the Engine reference
public class Car
private final Engine engine; // always has an engine
engine = new Engine();
Simply by tagging a field with
final, we have just created a very strong condition
on all Car instances: namely, they must have an Engine to exist. This simple
property can dramatically raise the quality of your code, by
aggregation relationships between objects. The object thus defined, and
all its aggregated dependents, always exists in a stable state.
Design by Contract is an effective programming methodology for designing robust
software components: by declaring (and verifying) conditions specific to a
given component, its behavior can be asserted correct, even at runtime.
final is a great tool to enforce field invariance: since final fields can
only be set once, any attempt to reset their value (accidental or not)
is detected by the compiler.
This idiom is also of great help during refactoring: it catches
refactoring mistakes by acting as a safeguard against the re-initialization of a
A caveat applies here: if a final variable holds a reference to an object,
the object may be modified, in spite of it being final.
This is because
final only applies to the reference holding
the object, not the object itself.
The final variable will always refer to the same object, but the object itself may change
through its methods.
This applies also to arrays and collections, because they are both objects. If
a final variable holds a reference to an array, then the components of the array
may be changed by operations on the array, although the variable will always refer to
the same array.
The same restriction applies to collections as well. E.g. a list
may be declared final and thus always exist as far as the aggregating object is concerned, its
content is undetermined, and can be changed at will. Elements can be added/removed
from the collection, even though it is declared final.
The revised memory model proposed by JSR 133 includes special provisions for final fields,
provisions that are absent from the existing specification. Newer VMs already implement this
specification, and treat final fields accordingly. Because final fields are assigned exactly once,
in a multithreaded context become possible. Specifically, a field doesn't need to be ever reloaded,
since its value is guaranteed never to change.
Conclusion on Final Fields
Extensive use of final fields leads to a new and interesting programming
idiom. By statically enforcing field initialization at
construction time, objects can be designed to be correct,
once their construction is complete. Doing so is a simple yet powerful way
to increase both the correctness and robustness of a given object: since it cannot fail to be
correctly initialized, subsequent methods are free to deal with their
own processing, and use whatever fields they need to do said processing,
without concern for the correct initialization sequence of the object.
This idiom strongly relates to eager initialization:
all fields are initialized
as soon as possible, at construction, and never changed once the
initialization phase is over.
In my experience, developers shun eager initialization because
it is perceived as more expensive than lazy initialization. "I don't need this
field until later, so let's not bother with it now," their thinking goes.
Unfortunately, this line
of thinking leads to more complex code that simply initializing all
fields right away. Every usage of the field has to check whether
the field has been initialized, and initialize it if it hasn't. It's akin to premature
optimization, which, as we all know, is the root of all evil.
Compare the two following examples. While it may look like a trivial
transformation, in a real class with potentially dozens of fields,
eager initialization will clear up a lot of code by removing
extraneous tests. By declaring all fields final, initialization is gathered in one place (the constructor),
yielding simpler, more maintainable, code.
public class LazyCar
private Engine engine; // lazily initialized
public void drive()
if (engine == null)
engine = new Engine();
public class BetterCar
private final Engine engine = new Engine(); // using final
public void drive()
// the engine is always present
A final method is implemented exactly once,
in the declaring class. Such a method cannot be overridden: subclasses cannot substitute a
new definition for the method.
Note that either modifier
static also implies
final, which is therefore redundant,
when applied to methods. Private and static methods
are always implicitely final, since they cannot be overridden.
Enforce Invariant Code
The Template Method pattern declares an abstract method
solely for the purpose of overriding it in a subclass. This allows the base class
to delegate parts of an algorithm to subclasses.
Final methods cannot be overridden, therefore
they create an almost exact anti-"template method" pattern. But in fact, they are
best used in conjonction with template methods. By specifying explicitely
which parts of the algorithm can vary (using abstract methods) and which cannot
(using final methods), the class's author conveys a precise picture of the work
expected by subclasses.
Final methods are used with template methods to declare the invariant parts of an algorithm.
public abstract class AbstractBase
public final void performOperation() // cannot be overridden
protected abstract void doPerformOperation(); // must override
Be aware that final methods impose a very strict restriction on subclass implementors.
In a framework context, think long and hard before declaring methods final, as it will
severely limit the extensibility of the framework, and the possibilities of adapting the
framework to situations unforeseen by the original developers.
In Java all methods are by default overridable. While this gives maximum flexibility to us
programmers, this liberal attitude can sometimes lead to conflicting situations.
Let's look at the
class for example. It declares methods that certainely must be overridable:
are two well-known examples.
Object also includes methods such as
– system-level methods which implement
core language capabilities.
It simply cannot be allowed for
to be substituted by a different implementation. It would alter
the semantics of the language itself.
Final methods come to the rescue again in this case:
final, and therefore it cannot be changed, accidentally or not. This reasoning also applies to entire
JDK classes, as discussed below.
Since a final method is only implemented in the declaring class, there is no need to dynamically
dispatch a call to a final method, and static invocation can be used instead.
The compiler can emit a direct call to the method, bypassing entirely the usual virtual
method invocation procedure.
Because of this, final methods are also candidates for inlining by a Just-In-Time compiler or a
similar optimization tool. (Remember, private/static methods are already final, therefore always
considered for this optimization.)
Static invocation is faster than dynamic method lookup, leading to the widespread use of final methods
as an optimization technique.
But this "optimization" is next to useless in recent virtual machines: they are able to detect if
a non-final method is overridden, and if not, use static invocation.
final should be used first and foremost for sofware engineering reasons, as
discussed in the rest of this article.
A final class cannot be subclassed, or extended, in any way. Final classes can be regarded as a
generalization of final methods: a final class has all its method declared final. On the other
hand, fields of final class do not have any special property.
Enforce Composition over Inheritance
Since final classes cannot be extended, the only way to reuse them is by composing them with
other objects. And encouraging that practice in your own code
might prove very healthy; inheritance, while a powerful
technique that should not be dismissed, has it own share of issues. It introduces a very tight
coupling between classes, sometimes leading to the infamous
Fragile Base Class problem.
It is also more complex, forcing users
to bounce up and down a class hierarchy in order to understand what a given class does.
And finally, it can break encapsulation by allowing less restrictive access to methods.
Thus final classes are used to enforce composition. This is particularly important with core
classes, classes that define the base functionality of a framework. We look at this case next.
One of the very best feature of the Java environment is its ability to dynamically load
classes. Necessarily, this flexibility comes at a price, including a more complex
security model. If classes can be loaded dynamically, at any time, the virtual machine must be able
to enforce security policies on the running code.
Final classes are used in this context to prevent malicious code from altering the semantics of classes
essential to the framework.
The best known example of a final class is certainely
This class is so vital to the operation of the Java compiler and interpreter
that it must be guaranteed that whenever code uses a string,
it gets exactly a
java.lang.String and not an instance of some other class.
java.lang.String is final, it cannot be subclassed,
none of its methods can be overriden, and therefore any
String instance is guaranteed to always
behave the way it is intended.
I would like to conclude this article with a section about immutable objects and
what a useful pattern they form.
An immutable object is an object which state is guaranteed to stay
identical over its entire lifetime. While it is perfectly possible to
implement immutability without
final, its use makes that
purpose explicit, to the human (the software developer) and the
machine (the compiler).
Immutable objects carry some very desirable characteristics:
- they are simple to understand and easy to use
- they are inherently thread-safe: they require no synchronization
- they make great building blocks for other objects
final is going to help us define immutable objects. First in labelling our object
as immutable, which makes it simple to use and understand by other programmers. Second
in guaranteeing that the object's state never changes, which enable the thread-safe property:
issues are relevant when one thread can change data while another thread is reading
the same data. Because an immutable object never changes its data, synchronizing
access to it is not needed.
Create an immutable class by meeting all of the following conditions:
- Declare all fields
- Set all fields in the constructor.
- Don't provide any methods that modify the state of the object; provide only getter methods (no setters).
- Declare the class final, so that no methods may be overridden.
- Ensure exclusive access to any mutable components, e.g. by returning copies.
I hope you have enjoyed this scrutiny of a sometimes forgotten feature of the Java language.
My references section lists additional resources useful to the reader eager
to keep on learning about
final and its uses.
About the Author
Renaud Waldura is a software engineer who develops distributed applications in Java.
He relishes in dissecting the subtleties of programming languages, as well as leading
software teams to success on complex projects.
Visit Renaud's Web site at http://renaud.waldura.com
and learn more about how his outstanding Java skills can help you succeed in your business.
Copyright © 2000-2003 by Renaud Waldura.
Permission to make digital or hard copies of part or all of this work for personal
or classroom use is granted without fee, provided that copies are not made or distributed
for profit or commercial advantage, and that copies bear this notice and full citation
on the first page.
Copyright for components of this work owned by others than Renaud Waldura
must be honored. Abstracting with credit is permitted. To copy otherwise, to
republish, to post on servers, or to redistribute to lists, requires prior
specific permission and/or fee. Request permission to publish from
Last modified: 2002/08/01 01:17:49 $