Where is final used?

There are a lot of Java developers that don’t understand the keyword final. The keyword final is one of your greatest allies in writing bug free maintainable code. It makes reading code much more deterministic and step debugging a breeze. And it makes your code side effect free.

Side effects are on of the most common causes of bugs and instability in imperative programming, and one of the most difficult to discover and correct.

One reason most people don’t understand why final is such a powerful keyword, is that it has two distinct meanings and most people only really understand the first.

Marking a class as final

The most popular understanding of why to use the keyword final is in marking a class as final. This makes sure that no one can sub-class the class that is marked final. This is like putting a sub class lock on your code, it means that the original developer intends that this behavior should never change.

Marking a method as final

Another similar use to the class usage, but much less known, is to mark a method as final. This is a seen in much rarer cases than marking an entire class as final. It locks the method so that sub classes can’t override the behavior of the method and shows the intent of the original developer that this should never change.

Marking a variable reference as final

The second most popular understanding of why to use the keyword final is to mark variables as final, this one is also the most misunderstood. This does something completely different than its use as a class or method modifier. It shows the intention of the original developer that the reference to an object or primitive should be immutable and trying to change it should result in an error.

final vs immutable

Some clarification is in order here, because there seems to be a lot of confusion about what is actually immutable when a variable reference is marked final.

It is the variable reference that is immutable, not the Object itself.

When someone refers to an Object as immutable, such as

The String object is immutable

they mean the internal state of the String object can never change, this is completely different than

the variable X is marked final and thus immutable.

Marking a variable final doesn’t magically make the Object instance that it is refering to immutable.

Lets take the following example:

private final List people = new ArrayList();

What this states is that the reference people can not be changed to point to a different instance of List.

It does not modify the behavior of the ArrayList implemenation in any way. The instance of the ArrayList can still be modifed. Person objects can be added and removed which mutates the ArrayList as it normally would.

What the final keyword does here is shows the intention of the original developer, that what the people variable refers to should never change.

If you later executed these instructions your code would not compile.

this.people = new ArrayList();

When should I use the keyword final?

Best practices show that you should use the keyword final as liberally as possible. The restrictions that final puts on what it is modifying always makes code easier to understand the intentions of the original developer and makes understanding the logic easier and makes step debugging easier as well.

Since marking a class or method as final is pretty explanatory and you can reason fairly easily why this is done and what its benefits are I am going to discuss why you should always strive to mark as many variable references final as possible.

The first two rules are fairly easy to implement, and show the most benefit when used

Always mark arguments to constructors and methods as final

public class Person(final String firstName, final String lastName)

public int getNextDay(final Date date)

This is a very powerful tool to help create easy to understand, and maintainable code, it shows to everyone that the arguments to never change. If they never change, as you read through the code to understand it you can be guaranteed that the argument values are consistent everywhere they are reference, they always referent to the same values that were passed in.

Always mark local variable final

One of the hardest things to debug is some long method that re-assigns a value over and over again in many different decision making constructs. Nested if/elseif/else statements and try/catch/finally blocks that re-use and mutate a local variable make it very difficult to statically reason what the expected behavior of the code is. It makes the method one big ad-hoc state machine. And the only way to understand the behavior is to step debug through the code, or worse pepper it with print statements all through it in an attempt to trace what the behavior is depending on the inputs.

It also makes it very easy for someone to come along behind you and break something un-intentionally because they have re-assigned something and broken your ad-hoc state machine.

Functional languages like Erlang have single assignment variables as a core part of their paradigm, and they tend to be more deterministic, easier to read and reason about what the intention of the logic is and less buggy because there is never a huge ad-hoc state machine.

Marking all instance variable references final

This one is harder to stick to consistently from a conceptual stand point. Mainly because it goes against everything most Java developers have ever know. But the rewards for learning to apply this practice are tremendous.

The first benefit is you get all the same benefits as marking arguments and local variables as final. You get easier to read and understand the intention of the original developer, you get simpler debugging and no side effects.

The second benefit of marking all instance variables as final is that you gain thread safety immediately, when all instance variables are final it makes the instance of the class immutable. Immutable instances can be shared without any locking semantics among as many threads as you wish since there is never the chance of data changing, so that means no contention and no race conditions.

Dealing with immutable data might seem like a hassle, but as soon as you start working with the data structures concurrently, dealing with immutable data structures is simple compared to dealing with concurrency primitives, locks, semaphores, synchronized blocks, counters and all the other baggage and boilerplate overhead that comes with concurrency in Java. All that concurrency overhead is extra code to be tested, debugged and maintained.

There is a performance angle as well

In previous versions of the JVM marking any variable references, instance, local and arguments as final allowed the compiler to do some advanced optimizations through caching because it could be sure that the contents of the variable reference never changed. This combined with immutable objects made a significant difference in concurrent code execution. In the case of final String declarations the compiler can aggressively optimize those out to almost nothing, since final String declarations are considered string literals if you concatenate string literals with + it can just convert them all to one single string literal.

Some of the performance aspects of the final keyword from previous compilers are handled with the most current JIT, but using final just for performance isn’t what this article is about, it is about increasing the quality of your code base, making your logic easier to discern the intention of the developer and making it more maintainable over the long run. Performance enhancements are just a bonus to these practices.

So the final word on final is

Try to apply the final modifier everywhere you can to make as many variables as possible single assignment, the more you do it the more you will appreciate the entire class of bugs and logic complications it allows you to eliminate through the single assignment variable idiom.