1
/
5

Best practices for using final keyword in Java

Photo by Markus Spiske on Unsplash

Role of final in Java

The same final keyword can be used in various contexts and play completely different roles in each of them. In short, there are five applications of final keyword:

  • Final classes. Such classes cannot be extended.
final class SomeClass { 
}
  • Final methods. Such methods cannot be overridden in subclasses.
class SomeClass {
  public final void someMethod() {
  }
}
  • Final method parameters. Such arguments cannot be reassigned within the method body.
class SomeClass {
  public void someMethod(final int someArgument) {
  }
}
  • Final fields. Such fields are guaranteed to be set during object construction and cannot be reassigned later on.
class SomeClass {
  final int someField = 42;
}
  • Final local variables. Such variables cannot be reassigned after they were assigned once.
class SomeClass {
  public void someMethod() {
    final int someVariable = getVar();
  }
}

In this article, we will talk about the last three, mostly about local variables. Even though all of them can be used in your code, some best practices were accumulated by the Java community. These practices might make your code more readable and less error-prone.

Best practices for final in method parameters

Let us start with the easiest one. Here is an example of a method with three parameters.

// with finals
class SomeClass {
  public void someMethod(final int arg1, final int arg2, final int arg3) {
  }
}

The consensus is, such code looks cluttered and the negative effect of finals on the readability is far greater than the safety it provides.

// without finals
class SomeClass {
  public void someMethod(int arg1, int arg2, int arg3) {
  }
}

Even though most developers agree, it is best to ensure the parameters are never reassigned, but most decide to catch such things during the review. It would be great if the final behavior for parameters was the default, but it is not the case.

Summary: DO NOT use final for method parameter unless you are in a project that uses such approach.

Best practices for final in class fields

There are very few cases where you have to reassign class fields. Mostly in modern development, we manipulate immutable objects, and class fields hold references to the class dependencies.

It is important to understand, that final does not make the object in the field immutable, but at least the reference is protected. This means you will have to work on the immutability of the object separately, but your first step is to make your field final.

Summary: DO use final for class fields in all cases unless you are absolutely sure you will have to reassign the field for a good reason.

Best practices for final in local variables

This final cause the most disagreement in the Java community. At the first sight, it might look very similar to the method parameters situation, the effect is the same - cannot reassign it in the method. But contrary to method parameters, which are normally never reassigned, there are many cases where the local variable is. This makes final a useful tool to demonstrate the intention of the developer in the code.

Let's consider several examples where the final might be useful.

Simulating expressions

Many modern languages, especially those which adopt functional paradigms, allow the usage of expressions to assign a value to a variable. Java does not have such syntax, but final can help us get as close as possible to such expressions.

public void someMethod() {
  final String result;
  if (someValue == 200) {
    result = "SUCCESS";
  } else {
    result = "FAIL;
  }
  ...
}

This very simple example tells the reader, that:

  • The result will be definitely assigned, there is no code pass that will let the result remain unassigned. Otherwise, the code will not compile.
  • The result will be set to the output of the if-else expression and will never be reassigned again.

This is a lot of information to give with just one additional keyword.

The same works for switch-cases, but it might be better to use new switch expressions from Java 12+.

Long methods

One might say “If your method is too long - split it” and generally would be completely right. In reality, we might have methods with a flow of logic that we don’t want to split. Splitting might reduce readability, make flow hidden in purely named functions.

In such cases, it becomes much more important to let the reader know which local variables are there to be assigned once and considered constants from that point on, and which ones are there to mutate throughout the method execution. The final can be used for this purpose.

Summary

It is very hard to make a formal strict rule about the usage of final for local variables in your code. Useful cases mentioned above can give you ideas of when to use final, in all other cases you can probably avoid it without losing much readability and declutter your code by keeping lines shorter.

株式会社ビービット's job postings
8 Likes
8 Likes

Weekly ranking

Show other rankings
Invitation from 株式会社ビービット
If this story triggered your interest, have a chat with the team?