Does use of final keyword in Java improve the performance?

105,750

Solution 1

Usually not. For virtual methods, HotSpot keeps track of whether the method has actually been overridden, and is able to perform optimizations such as inlining on the assumption that a method hasn't been overridden - until it loads a class which overrides the method, at which point it can undo (or partially undo) those optimizations.

(Of course, this is assuming you're using HotSpot - but it's by far the most common JVM, so...)

To my mind you should use final based on clear design and readability rather than for performance reasons. If you want to change anything for performance reasons, you should perform appropriate measurements before bending the clearest code out of shape - that way you can decide whether any extra performance achieved is worth the poorer readability/design. (In my experience it's almost never worth it; YMMV.)

EDIT: As final fields have been mentioned, it's worth bringing up that they are often a good idea anyway, in terms of clear design. They also change the guaranteed behaviour in terms of cross-thread visibility: after a constructor has completed, any final fields are guaranteed to be visible in other threads immediately. This is probably the most common use of final in my experience, although as a supporter of Josh Bloch's "design for inheritance or prohibit it" rule of thumb, I should probably use final more often for classes...

Solution 2

Short answer: don't worry about it!

Long answer:

When talking about final local variables keep in mind that using the keyword final will help the compiler optimize the code statically, which may in the end result in faster code. For example, the final Strings a + b in the example below are concatenated statically (at compile time).

public class FinalTest {

    public static final int N_ITERATIONS = 1000000;

    public static String testFinal() {
        final String a = "a";
        final String b = "b";
        return a + b;
    }

    public static String testNonFinal() {
        String a = "a";
        String b = "b";
        return a + b;
    }

    public static void main(String[] args) {
        long tStart, tElapsed;

        tStart = System.currentTimeMillis();
        for (int i = 0; i < N_ITERATIONS; i++)
            testFinal();
        tElapsed = System.currentTimeMillis() - tStart;
        System.out.println("Method with finals took " + tElapsed + " ms");

        tStart = System.currentTimeMillis();
        for (int i = 0; i < N_ITERATIONS; i++)
            testNonFinal();
        tElapsed = System.currentTimeMillis() - tStart;
        System.out.println("Method without finals took " + tElapsed + " ms");

    }

}

The result?

Method with finals took 5 ms
Method without finals took 273 ms

Tested on Java Hotspot VM 1.7.0_45-b18.

So how much is the actual performance improvement? I don't dare say. In most cases probably marginal (~270 nanoseconds in this synthetic test because the string concatenation is avoided altogether - a rare case), but in highly optimized utility code it might be a factor. In any case the answer to the original question is yes, it might improve performance, but marginally at best.

Compile-time benefits aside, I could not find any evidence that the use of the keyword final has any measurable effect on performance.

Solution 3

YES it can. Here is an instance where final can boost performance:

Conditional compilation is a technique in which lines of code are not compiled into the class file based on a particular condition. This can be used to remove tons of debugging code in a production build.

consider the following:

public class ConditionalCompile {

  private final static boolean doSomething= false;

    if (doSomething) {
       // do first part. 
    }

    if (doSomething) {
     // do second part. 
    }

    if (doSomething) {     
      // do third part. 
    }

    if (doSomething) {
    // do finalization part. 
    }
}

By converting the doSomething attribute into a final attribute, you have told the compiler that whenever it sees doSomething, it should replace it with false as per the compile-time substitution rules. The first pass of the compiler changes the code to something like this:

public class ConditionalCompile {

  private final static boolean doSomething= false;

    if (false){
       // do first part. 
    }

    if (false){
     // do second part. 
    }
 
    if (false){
      // do third part. 
    }
   
    if (false){
    // do finalization part. 

    }
}

Once this is done, the compiler takes another look at it and sees that there are unreachable statements in the code. Since you are working with a top-quality compiler, it doesn't like all those unreachable byte codes. So it removes them, and you end up with this:

public class ConditionalCompile {


  private final static boolean doSomething= false;

  public static void someMethodBetter( ) {

    // do first part. 

    // do second part. 

    // do third part. 

    // do finalization part. 

  }
}

thus reducing any excessive codes, or any unnecessary conditional checking.

Edit: As an example, let's take the following code:

public class Test {
    public static final void main(String[] args) {
        boolean x = false;
        if (x) {
            System.out.println("x");
        }
        final boolean y = false;
        if (y) {
            System.out.println("y");
        }
        if (false) {
            System.out.println("z");
        }
    }
}

When compiling this code with Java 8 and decompiling with javap -c Test.class we get:

public class Test {
  public Test();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  public static final void main(java.lang.String[]);
    Code:
       0: iconst_0
       1: istore_1
       2: iload_1
       3: ifeq          14
       6: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
       9: ldc           #22                 // String x
      11: invokevirtual #24                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      14: iconst_0
      15: istore_2
      16: return
}

We can note that compiled code includes only the non-final variable x. This prooves that final variables have impact on performances, at least for this simple case.

Solution 4

According to IBM - it doesnt for classes or methods.

http://www.ibm.com/developerworks/java/library/j-jtp04223.html

Solution 5

I am amazed that no one has actually posted some real code that is de-compiled to prove that there is at least some minor difference.

For the reference this has been tested against javac version 8, 9 and 10.

Suppose this method:

public static int test() {
    /* final */ Object left = new Object();
    Object right = new Object();

    return left.hashCode() + right.hashCode();
}

Compiling this code as it is, produces the exact same byte code as when final would have been present (final Object left = new Object();).

But this one:

public static int test() {
    /* final */ int left = 11;
    int right = 12;
    return left + right;
}

Produces:

   0: bipush        11
   2: istore_0
   3: bipush        12
   5: istore_1
   6: iload_0
   7: iload_1
   8: iadd
   9: ireturn

Leaving final to be present produces:

   0: bipush        12
   2: istore_1
   3: bipush        11
   5: iload_1
   6: iadd
   7: ireturn

The code is pretty much self-explanatory, in case there is a compile time constant, it will be loaded directly onto the operand stack (it will not be stored into local variables array like the previous example does via bipush 12; istore_0; iload_0) - which sort of makes sense since no one can change it.

On the other hand why in the second case the compiler does not produce istore_0 ... iload_0 is beyond me, it's not like that slot 0 is used in any way (it could shrink the variables array this way, but may be Im missing some internals details, can't tell for sure)

I was surprised to see such an optimization, considering how little ones javac does. As to should we always use final? I'm not even going to write a JMH test (which I wanted to initially), I am sure that the diff is in the order of ns (if possible to be captured at all). The only place this could be a problem, is when a method could not be inlined because of it's size (and declaring final would shrink that size by a few bytes).

There are two more finals that need to be addressed. First is when a method is final (from a JIT perspective), such a method is monomorphic - and these are the most beloved ones by the JVM.

Then there are final instance variables (that must be set in every constructor); these are important as they will guarantee a correctly published reference, as touched a bit here and also specified exactly by the JLS.


That being said : there is one more thing that is invisible to every single answer here: garbage collection. It is going to take a lot of time to explain, but when you read a variable, a GC has a so-called barrier for that read. Every aload and getField is "protected" via such a barrier, a lot more details here. In theory, final fields do not need such a "protection" (they can skip the barrier entirely). So if a GC does that - final will improve performance.

Share:
105,750
Abhishek Jain
Author by

Abhishek Jain

Updated on July 08, 2022

Comments

  • Abhishek Jain
    Abhishek Jain almost 2 years

    In Java we see lots of places where the final keyword can be used but its use is uncommon.

    For example:

    String str = "abc";
    System.out.println(str);
    

    In the above case, str can be final but this is commonly left off.

    When a method is never going to be overridden we can use final keyword. Similarly in case of a class which is not going to be inherited.

    Does the use of final keyword in any or all of these cases really improve performance? If so, then how? Please explain. If the proper use of final really matters for performance, what habits should a Java programmer develop to make best use of the keyword?

  • Abhishek Jain
    Abhishek Jain over 13 years
    I like your answer but I would like to know more in details about it.
  • Jon Skeet
    Jon Skeet over 13 years
    @Abhishek: About what in particular? The most important point is the last one - that you almost certainly shouldn't be worrying about this.
  • Abhishek Jain
    Abhishek Jain over 13 years
    As I have written above in one comment, PMD tool suggest me that particular kind of change but I did not understand the context of the above changes. Yes I am agree with you even I did not find any difference. There are lots of articles related to performance suggest this change. So I would like to know what difference JVM actually make with final keyword and else ...if possible. +1 for your answer.
  • sleske
    sleske over 13 years
    @Abishek: final is generally recommended because it makes code easier to understand, and helps find bugs (because it makes the programmers intention explicit). PMD probably recommends to use final because of these style issues, not for performance reasons.
  • Jon Skeet
    Jon Skeet over 13 years
    @Abhishek: A lot of it is likely to be JVM-specific, and may rely on very subtle aspects of context. For example, I believe the HotSpot server JVM will still allow inlining of virtual methods when overridden in one class, with a quick type check where appropriate. But the details are hard to pin down and may well change between released.
  • mel3kings
    mel3kings over 10 years
    @ŁukaszLech I learned this from an Oreilly book: Hardcore Java, on their chapter regarding the final keyword.
  • gyorgyabraham
    gyorgyabraham over 10 years
    I don't think the compiler can correctly check the number of times a local variable is assigned: what about if-then-else structs with numerous assignments?
  • sleske
    sleske over 10 years
    @gyabraham: The compiler already checks theses cases if you declare a local variable as final, to make sure you do not assign it twice. As far as I can see, the same checking logic can be (and probably is) used for checking whether a variable could be final.
  • gyorgyabraham
    gyorgyabraham over 10 years
    By "object is final" you mean "object is immutable".
  • Bhavesh Agarwal
    Bhavesh Agarwal over 10 years
    This talks about optimization at the compile time, means developer knows the VALUE of the final boolean variable at compile time, what is the whole point of writing if blocks in first place then for this scenario where the IF-CONDITIONS are not necessary and not making any sense? In my opinion, even if this boosts performance, this is wrong code in first place and can be optimized by developer himself rather than passing the responsibility to compiler and the question mainly intends to ask about the performance improvements in usual codes where final is used which makes programmatic sense.
  • Casper Færgemand
    Casper Færgemand about 10 years
    I rewrote your code a little to test both cases 100 times. Eventually the average time of the final was 0 ms and 9 ms for the non final. Increasing the iteration count to 10M set the average to 0 ms and 75 ms. The best run for the non final was 0 ms however. Maybe it's the VM detecting results are just being thrown away or something? I don't know, but regardless, the use of final does make a significant difference.
  • Steve Kuo
    Steve Kuo almost 10 years
    Flawed test. Earlier tests will warmup the JVM and benefit the later test invocations. Reorder your tests and see what happens. You need to run each test in its own JVM instance.
  • Steve Kuo
    Steve Kuo almost 10 years
    The final-ness of a local variable is not expressed in the bytecode, thus the JVM doesn't even know that it was final
  • sleske
    sleske almost 10 years
    @SteveKuo: Even if it is not expressed in the bytecode, it may help javac to optimize better. But this is just speculation.
  • rustyx
    rustyx almost 10 years
    No the test is not flawed, the warmup was taken into account. The second test is SLOWER, not faster. Without warmup the second test would be EVEN SLOWER.
  • anber
    anber almost 10 years
    In testFinal() all time returned the same object, from strings pool, because resust of final strings and strings literals concatenation are evaluated at compile time. testNonFinal() every time return new object, thats explain difference in speed.
  • Kai
    Kai over 9 years
    Changing String a and b to Integers results in no performance difference. @anber is right this benchmark is flawed. It is not related to any realistic scenario.
  • rustyx
    rustyx over 9 years
    What makes you think the scenario is unrealistic? String concatenation is a much more costly operation than adding Integers. Doing it statically (if possible) is more efficient, that's what the test shows.
  • Javamann
    Javamann almost 9 years
    I was told that adding the final modifier to a variable is a hint to the JIT that the variable could be stored in a CPU register for faster access.
  • Louis F.
    Louis F. over 8 years
    Here I would quote Effective Java, 2nd Edition, Item 15, Minimize mutability : Immutable classes are easier to design, implement, and use than mutable classes. They are less prone to error and are more secure.. Furthermore An immutable object can be in exactly one state, the state in which it was created. vs Mutable objects, on the other hand, can have arbitrarily complex state spaces.. From my personal experience, using the keyword final should highlight the intent of the developer to lean toward immutability, not to "optimize" code. I encourage you to read this chapter, fascinating !
  • Adam
    Adam about 8 years
    The point of this would be to add debugging statements as mel3kings stated. You could flip the variable before a production build (or configure it in your build scripts) and automatically remove all of that code when the distribution is created.
  • Honza Zidek
    Honza Zidek almost 8 years
    You are right, but you are not answering the question. OP did not ask what final means, but whether using final influence the performance.
  • Holger
    Holger over 7 years
    The compiler could find out whether a local variable has been assigned exactly once, but in practice, it doesn’t (beyond error checking). On the other hand, if a final variable is of a primitive type or type String and is immediately assigned with a compile-time constant like in the question’s example, the compiler must inline it, as the variable is a compile-time constant per specification. But for most use cases, the code might look different, but it still makes no difference whether the constant is inlined or read from a local variable performance-wise.
  • Anticro
    Anticro over 7 years
    You forgot to make the parameters final. <pre><code> public ShaderInput x(final int stride, final float val) { input[strides[stride] + 0] = val; return this; } </code></pre> In my experiences, doing any variable or field final may indeed boost performance.
  • Anticro
    Anticro over 7 years
    Oh, and also make the others final too: <pre><code> final int arraySize = 10; final float[] fb = new float[arraySize]; for (int i = 0; i < arraySize; i++) { fb[i] = random.nextFloat(); } final int times = 1000000000; for (int i = 0; i < 10; ++i) { floatVectorTest(times, fb); arrayCopyTest(times, fb); shaderInputTest(times, fb); directFloatArrayTest(times, fb); System.out.println(); System.gc(); } </code></pre>
  • El Mac
    El Mac about 7 years
    @RustyX but that's because of the Stringpool? So with any other type of object, it would not work?
  • Gergely Toth
    Gergely Toth almost 7 years
    If you pass in the loop variable i to the methods testFinal and testNonFinal and in these methods instead of returning a + b you return a + i + b then the execution times are identical, as in fact the generated bytecodes are identical
  • Eugene
    Eugene about 6 years
    @JonSkeet this is yet again (you probably dont even keep track of this, which is good) one of those questions where the answer would be "don't bother with these details, do a clear design, etc", unless you are all about these details... stackoverflow.com/a/49417253/1059372
  • Julien Kronegg
    Julien Kronegg about 6 years
    Other answers shows that using the final keyword on variables could reduce the amount of bytecode, which may produce an effect on performance.
  • Julien Kronegg
    Julien Kronegg about 6 years
    I compiled the code using Java 8 (JDK 1.8.0_162) with the debug options (javac -g FinalTest.java), decompiled the code using javap -c FinalTest.class and did not obtain the same results (with final int left=12, I got bipush 11; istore_0; bipush 12; istore_1; bipush 11; iload_1; iadd; ireturn). So yes, the generated bytecode dependents on lot of factors and it is difficult to say whether having a final or not produce an effect on performance. But as the bytecode is different, some performance difference may exist.
  • user202729
    user202729 almost 6 years
  • Philzen
    Philzen over 4 years
    ...and according to IBM, it does for fields: ibm.com/developerworks/java/library/j-jtp1029/… - and also is promoted as a best practice.
  • dmatej
    dmatej over 4 years
    The article "04223" is from year 2003. Nearly seventeen years old now. That was ... Java 1.4?
  • maaartinus
    maaartinus almost 4 years
    There's NOTHING preventing the JIT to throw away both test methods as the results doesn't get used. The JIT doesn't bother or maybe it's just kind enough to provide you some figures, but the timing could be all zero. See JMH blackhole for how to do it right.
  • Stefan Reich
    Stefan Reich over 3 years
    It's not terribly interesting though what the byte code looks like. Actual assembly code is all that matters. I well suspect that in this case the assembly will ultimately look the same.
  • Ashley Frieze
    Ashley Frieze over 3 years
    Adding extra annotations and finals to code makes it bigger... but does it really make it better?
  • Bill K
    Bill K about 3 years
    Absolutely, and much better. Coding is not typing stuff to make something work, that's basically scriptwriting (which is a totally valid practice, but I wouldn't recommend java for it). Final saves so may problems (and doesn't really make your program bigger--unless for some horrific reason you mean to minimize source code size which is a terrifying concept--why not just code in APL or one of the code-golf languages if that is your goal? Using your code to prevent issues before you encounter them is amazingly useful.
  • Ashley Frieze
    Ashley Frieze about 3 years
    Sure... but... I've seen code with deep rooted issues with final all over the place, and I've seen beautifully easy code without it. How does final specifically help in a way that other practices don't? For example, if you only write very very short functions, and rarely use temp variables, final doesn't add so much as look like SHOUTING! ;)
  • Philzen
    Philzen about 2 years
    "~270 nanoseconds in this synthetic test" ... but isn't it microseconds?
  • blau
    blau about 2 years
    Wonderful point in mentioning cross-thread visibility as an added bonus to using final.