The Java final modifier, What is the right way to use it ?, How do I enforce the right way ?
In Java, all methods and instance variables can be overridden by default.
If you wish to declare that you want to no longer allow subclasses to override your variables or methods, you can declare them with final
modifier.
The final
modifier can be applied to four types of programming constructs in Java :
- variables in general: A
final
variable can be initialized only once. - class property : A
final
property/field/instance-variable can only be set at once, by the constructor of the class which defines it. - methods: You can use the
final
as a modifier on the method declarations when you want to refuse subclasses from overriding a particular method. - classes: A
final
class cannot be subclassed, or extended, in any way. Making a classfinal
is nothing but making all its methods and properties declaredfinal
.
More final
programming constructs give you better performance since it is easy for the compiler to consume them as they are in the fixed memory location, and there is no way for them to be virtually overridden.
There is a dichotomy in the universe right now on whether to enforce usage of final
where ever applicable or leave that to the programmer’s choice. Some feel it is noise while reading the code, some feel it is not so important.
Some usually justify such a Directive attitude by blaming JAVA in general for allowing the developers to create Fragile Base Class Problem.
There are solutions for avoiding such problems as well using Selective Open Recursion.
Irrespective of the Attitude you have
How do I as a Development Manager Enforce all my team members to use final
modifier for
- A method parameter that is never re-assigned within the method should be declared
final
- A class with only private constructors should be
final
unless the private constructor is invoked by an inner class. - A local variable assigned only once should be declared
final
Java Programming mistakes detector(PMD) provides an amazing set of rules which could be added to your project to enforce usage of final where ever it is logically applicable.
If you are using a maven PMD plugin, just copy the below contents and save them in a file called “final-pmd-rules.xml” in your desired location within the working directory.
<?xml version="1.0"?>
<ruleset name="Documentation"
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
<description>
Rules that for final modifier.
</description>
<rule ref="category/java/codestyle.xml/LocalVariableCouldBeFinal" />
<rule ref="category/java/design.xml/ClassWithOnlyPrivateConstructorsShouldBeFinal" />
<rule ref="category/java/codestyle.xml/MethodArgumentCouldBeFinal" />
</ruleset>
Now consume the PMD final rules that we just created in your PMD plugin goal.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>${maven.pmd.plugin.version}</version>
<configuration>
<linkXRef>false</linkXRef>
<sourceEncoding>UTF-8</sourceEncoding>
<targetJdk>${java.required.version}</targetJdk>
<rulesets>
<ruleset>${rootDir}/your/existing/rules.xml</ruleset>
<ruleset>${rootDir}/path/to/final-pmd-rules.xml</ruleset>
</rulesets>
</configuration>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
If you are using Gradle, you should first apply the PMD plugin if you have not used then configure the Gradle task like below by consuming the final PMD rules we just created.
apply plugin: 'pmd'
pmd {
consoleOutput = true
toolVersion = "6.22.0"
ruleSets = [
"${rootDir}/your/existing/pmd-rules-if-any.xml",
"${rootDir}/path/to/final-pmd-rules.xml"
]
}