What is the meaning of a single-use local variable being final?

Ryan Durel :

While working in an existing codebase I came across something similar to this.

public static int getDatePlusDaysInMillis(int days) {
    final int DAY = 24 * 60 * 60 * 1000;

    return System.currentTimeMillis() + DAY * days;
}

The logic itself is not important, as I modified the code a bit so I wasn't copying & pasting business code.

What I wanted to bring attention to was final int DAY. Is there any reason to declare DAY as final? It's scoped to this method and only used once within it. It's not hurting anything, but I thought it looked odd and wanted to ask if there is any meaning to this variable being declared final.

kaya3 :

Yes, there is a point to doing this. When declared final, the variable DAY is a constant variable as defined by the Java Language Specification (§4.12.4):

A constant variable is a final variable of primitive type or type String that is initialized with a constant expression (§15.28).

This means some optimisations are done at compile-time, which aren't done when the variable is not declared final. We can see the different bytecode depending on whether you use final or not:

public class Test {
    public long withoutFinal(int days) {
        int DAY = 24 * 60 * 60 * 1000;
        return System.currentTimeMillis() + DAY * days;
    }
    public long withFinal(int days) {
        final int DAY = 24 * 60 * 60 * 1000;
        return System.currentTimeMillis() + DAY * days;
    }
}

Compiles to:

  public long withoutFinal(int);
    Code:
       0: ldc           #2          // int 86400000
       2: istore_2
       3: invokestatic  #3          // Method java/lang/System.currentTimeMillis:()J
       6: iload_2
       7: iload_1
       8: imul
       9: i2l
      10: ladd
      11: lreturn

  public long withFinal(int);
    Code:
       0: invokestatic  #3          // Method java/lang/System.currentTimeMillis:()J
       3: ldc           #2          // int 86400000
       5: iload_1
       6: imul
       7: i2l
       8: ladd
       9: lreturn

The version with final is shorter, because it uses one ldc (load constant) operation where the other version uses a ldc, an istore_2 to store the constant to a local variable, and an iload_2 to load it from that local variable.

This difference would likely be optimised away at runtime by the JIT if the method is called many times, but using final means the .class file is slightly smaller, and there is a small performance benefit if the method is not called many times.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=31350&siteId=1