23

I've been using PMD to help spot potential problems in my Java code, and I've been finding its advice to be split between the useful, the idiosyncratic, and the "WTF?!".

One of the things it keeps telling me to do is to use the final keyword for literally every variable I can attach it to, including input parameters. For actual constants this seems sensible, but for other stuff it just strikes me as odd, possibly even a tad counterproductive.

Are there concrete advantages/disadvantages to hanging final on every variable declaration you possibly can?

BlairHippo
  • 9,502
  • 10
  • 54
  • 78

5 Answers5

28

"Every variable declaration you possibly can" sounds a bit extreme, but final is actually beneficial in many ways. Sometimes I wish that final was the default behavior, and required no keyword, but true "variables" required a variable modifier. Scala adopted something like this approach with its val and var keywords—using val (the final-like keyword) is strongly encouraged.

It is especially important to carefully consider whether each member variable is final, volatile, or neither, because the thread safety of the class depends on getting this right. Values assigned to final and volatile variables are always visible to other threads, without using a synchronized block.

For local variables, it's not as critical, but using final can help you reason about your code more clearly and avoid some mistakes. If you don't expect a value to change within a method, say so with final, and let the compiler find unnoticed violations of this expectation. I'm not aware of any that do currently, but it's easily conceivable that a JIT compiler could use this hint to improve performance too.

In practice, I don't declare local variables final whenever I could. I don't like the visual clutter and it seems cumbersome. But, that doesn't mean it's not something I should do.

A proposal has been made to add the var keyword to Java aimed at supporting type inference. But as part of that proposal, there have been a number of suggestions for additional ways of specifying local variable immutability. For example, one suggestion was to also add the key word val to declare an immutable variable with inferred type. Alternatively, some advocate using final and var together.

erickson
  • 265,237
  • 58
  • 395
  • 493
  • Seen in hindsight that would have been the best. It would, however, have broken C semantics which was explicitly sought to give C++ programmers an easy transition. – Thorbjørn Ravn Andersen Aug 24 '10 at 20:31
  • The JIT compiler doesn't need `final` on local variables at all, and _never_ did; it can see whether each variable is actually modified. Of course, what it sees and what the programmer sees are potentially quite different… – Donal Fellows Feb 12 '19 at 10:49
  • final doesn't guarantee thread-safety without synchronizing. final List can throw ConcurrentModificationException if you change the size of the list while other thread iterates it. Same goes for complex Objects, like DAO. Even if the DAO itself is final, some thread may mess up with the properties while other thread is reading them, and produce inconsistent states, so you would need a thread-safe DAO / List to ensure that final guarantees thread safety – DGoiko Jan 28 '20 at 21:17
  • @DGoiko I didn't say that it did, but thanks for the clarification. – erickson Jan 28 '20 at 21:21
  • oh, sorry, english is not my mother languaje and I may have sound rude. I just wanted to make a side-note – DGoiko Jan 28 '20 at 21:35
  • @DGoiko No problem, many readers will appreciate that additional info. – erickson Jan 28 '20 at 21:37
6

final tells the reader that the value or reference assigned first is the same at any time later.

As everything that CAN be final IS final in this scenario, a missing final tells the reader that the value will change later, and to take that into account.

Thorbjørn Ravn Andersen
  • 73,784
  • 33
  • 194
  • 347
  • That makes sense for primitives, or for immutable objects like String. But does that encourage a false sense of security for mutable objects? – BlairHippo Aug 24 '10 at 17:42
  • A missing final only tells you that it can change later, certainly not that it will. To assume so is simply wrong. If a class is not defined as final it may be subclassed, doesn't mean it is. The usage of final for all variables is open to debate (ofter here) so its absence can just as easily be attributed to coder preference. – Robin Aug 24 '10 at 18:49
  • 1
    @Robin, please note that the OP said "Everything's final". That is the case I am discussing. Please read the questions properly before downvoting the answers. – Thorbjørn Ravn Andersen Aug 24 '10 at 20:27
  • @BlairHippo, only if you do not understand the difference between the reference itself and the referenced object. What you are guaranteed is that the thing you have is the same - what is inside the thing is another matter (but in this particular case, there is a good chance there is a lot of finals too) – Thorbjørn Ravn Andersen Aug 24 '10 at 20:40
2

This is a common idiom for tools like PMD. For example, below are the corresponding rules in Checkstyle. It's really a matter of style/preference and you could argue for both sides.

In my opinion, using final for method parameters and local variables (when applicable) is good style. The "design for extension" idiom is debatable.

Taylor Leese
  • 51,004
  • 28
  • 112
  • 141
1

Here are some reason why it may be beneficial to have almost everything tagged as final

Final Constants

 public static class CircleToolsBetter {
     public final static double PI = 3.141;
        public double getCircleArea(final double radius) {
          return (Math.pow(radius, 2) * PI);
        }
    }

This can be used then for other parts of your codes or accessed by other classes, that way if you would ever change the value you wouldn't have to change them one by one.

Final Variables

public static String someMethod(final String environmentKey) {
    final String key = "env." + environmentKey;
    System.out.println("Key is: " + key);
    return (System.getProperty(key));

  }

}

In this class, you build a scoped final variable that adds a prefix to the parameter environmentKey. In this case, the final variable is final only within the execution scope, which is different at each execution of the method. Each time the method is entered, the final is reconstructed. As soon as it is constructed, it cannot be changed during the scope of the method execution. This allows you to fix a variable in a method for the duration of the method. see below:

public class FinalVariables {


  public final static void main(final String[] args) {
    System.out.println("Note how the key variable is changed.");
    someMethod("JAVA_HOME");
    someMethod("ANT_HOME");
  }
}

Final Constants

public double equation2Better(final double inputValue) {
    final double K = 1.414;
    final double X = 45.0;

double result = (((Math.pow(inputValue, 3.0d) * K) + X) * M);
double powInputValue = 0;         
if (result > 360) {
  powInputValue = X * Math.sin(result); 
} else {
  inputValue = K * Math.sin(result);   // <= Compiler error   
}

These are especially useful when you have really long lines of codes, and it will generate compiler error so you don't run into logic/business error when someone accidentally changes variables that shouldn't be changed.

Final Collections

The different case when we are talking about Collections, you need to set them as an unmodifiable.

 public final static Set VALID_COLORS; 
    static {
      Set temp = new HashSet( );
      temp.add(Color.red);
      temp.add(Color.orange);
      temp.add(Color.yellow);
      temp.add(Color.green);
      temp.add(Color.blue);
      temp.add(Color.decode("#4B0082")); // indigo
      temp.add(Color.decode("#8A2BE2")); // violet
      VALID_COLORS = Collections.unmodifiableSet(temp);
    }

otherwise, if you don't set it as unmodifiable:

Set colors = Rainbow.VALID_COLORS;
colors.add(Color.black); // <= logic error but allowed by compiler

Final Classes and Final Methods cannot be extended or overwritten respectively.

EDIT: TO ADDRESS THE FINAL CLASS PROBLEM REGARDING ENCAPSULATION:

There are two ways to make a class final. The first is to use the keyword final in the class declaration:

public final class SomeClass {
  //  . . . Class contents
}

The second way to make a class final is to declare all of its constructors as private:

public class SomeClass {
  public final static SOME_INSTANCE = new SomeClass(5);
  private SomeClass(final int value) {
  }

Marking it final saves you the trouble if finding out that it is actual a final, to demonstrate look at this Test class. looks public at first glance.

public class Test{
  private Test(Class beanClass, Class stopClass, int flags)
    throws Exception{
    //  . . . snip . . . 
  }
}

Unfortunately, since the only constructor of the class is private, it is impossible to extend this class. In the case of the Test class, there is no reason that the class should be final. The test class is a good example of how implicit final classes can cause problems.

So you should mark it final when you implicitly make a class final by making its constructor private.

Aman Chourasiya
  • 1,078
  • 1
  • 10
  • 23
mel3kings
  • 8,857
  • 3
  • 60
  • 68
1

PMD also has option rules you can turn on that complains about final; it's an arbitrary rule.

If I'm doing a project where the API is being exported to another team - or to the world - leave the PMD rule as it stands. If you're just developing something that will forever and always be a closed API, disable the rule and save yourself some time.

Dean J
  • 39,360
  • 16
  • 67
  • 93