Friday, March 10, 2017

The final keyword in Java

Most experienced Java developers are familiar with the final keyword. It can be used at three different levels: class, method, and variable (or field).

Probably the most common use of final is in the definition of constants, such as

public static final Integer MY_CONSTANT = 475;


Another common use is for local variables (or method parameters) whose value never changes:

String getNameAndAge() {
    final String name = determineName();
    final Integer age = determineAge();
    return name + " " + age;
}

That the values of name and age in the above example cannot be changed leads some to believe that the final keyword makes an object immutable. In a code review I was doing recently, I came across a snippet of code similar to the following:

// make the context immutable
final Context context = contextFactory.build(contextParameters);

The author had been told in a previous comment to make Context immutable, and this was their attempt to do so. To understand why this fails to make context immutable, it helps to recall how Java stores data.

Briefly, for primitive values, the value is stored directly in the stack. For the sake of visualization, we can say that the variable stores the value itself. For objects, however, the variable stores not the object, but a reference to the object. In other words, adding the final keyword only limits you from reassigning the reference that is stored by the variable.

This means that the final keyword in the above case means that you cannot assign a different Context instance to context, but you can use the setter methods in the Context class to modify the instance that you do have, so you do not have an immutable instance of Context. The way to make Context immutable is not in the use of final, but instead in removing the setter methods from the Context class itself. You cannot make an immutable instance of a class that is itself mutable.

As mentioned above, final can be used at the class level and at the method level as well. When used at the class level, it means that the class cannot be extended (see java.lang.String). When used at the method level, it means that the method cannot be overridden.

There are style issues around final as well, such as whether or not to label method parameters as final or whether final should be used on local variables at all. Style is a bit outside the scope of this article, but I urge you (and your team) to have a consistently used policy.

No comments:

Post a Comment