Abhishek Jain
Abhishek Jain

Reputation: 6366

Does use of final keyword in Java improve the performance?

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?

Upvotes: 417

Views: 123837

Answers (14)

Marco Carlo Moriggi
Marco Carlo Moriggi

Reputation: 414

In Java we make things immutable with the final keyword and there are at least 3 ways in which immutability can make some real difference in code performance. Those 3 points have their common origin in making the compiler or the developer doing better assumptions:

  1. More reliable code
  2. More performant code
  3. More efficient memory allocation and garbage collection

More reliable code

As stated by many of the other replies and comments, making classes immutable leads to cleaner and more maintainable code, and making objects immutable makes them easier to handle, because they can be in exactly one state, so this translates to easier concurrency and an optimization of the time needed to accomplish tasks.

Furthermore the compiler warns you about the usage of an uninitialized variable and won't let you reassign it with a new value.

If we talk about method parameters, declaring them final would make the compiler complaint if you accidentally use the same name for a variable, or reassign it's value (making the parameter no more accessible).

More performant code

A simple analysis of the generated bytecode should put the last world to the performance question: using a minimally modified version of the code posted by @rustyx in his reply, you can see that the generated bytecode is different when the compiler knows that objects won't mutate their value.

That's the code:

public class FinalTest {

    private static final int N_ITERATIONS = 1000000;

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

    private static String testNonFinal() {
        String a = "a";
        String b = "b";
        return a + b;
    }
    
    private static String testSomeFinal() {
        final String a = "a";
        String b = "b";
        return a + b;
    }

    public static void main(String[] args) {
        measure("testFinal", FinalTest::testFinal);
        measure("testSomeFinal", FinalTest::testSomeFinal);
        measure("testNonFinal", FinalTest::testNonFinal);
    }
    
    private static void measure(String testName, Runnable singleTest){
        final long tStart = System.currentTimeMillis();
        for (int i = 0; i < N_ITERATIONS; i++)
            singleTest.run();
        final long tElapsed = System.currentTimeMillis() - tStart;
        
        System.out.printf("Method %s took %d ms%n", testName, tElapsed);
    }
    
}

compiling it with openjdk17: javac FinalTest.java

then decompiling: javap -c -p FinalTest.class

lead to this bytecode:

  private static java.lang.String testFinal();
    Code:
       0: ldc           #7                  // String ab
       2: areturn

  private static java.lang.String testNonFinal();
    Code:
       0: ldc           #9                  // String a
       2: astore_0
       3: ldc           #11                 // String b
       5: astore_1
       6: aload_0
       7: aload_1
       8: invokedynamic #13,  0             // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
      13: areturn

  private static java.lang.String testSomeFinal();
    Code:
       0: ldc           #11                 // String b
       2: astore_0
       3: aload_0
       4: invokedynamic #17,  0             // InvokeDynamic #1:makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;
       9: areturn

// omitted bytecode for the measure() method, which is not interesting

As you can see, there are cases where the final keyword makes a difference.

For the sake of completeness those are the measured times:

Method testFinal took 5 ms
Method testSomeFinal took 13 ms
Method testNonFinal took 20 ms

Those times seems to be irrelevant (given that we accomplished 1 million tasks), but I think that, after some while, JIT optimization is doing it's magic and smooths out the differences, but even with that said, 4x is not that negligible, considering that, when it comes to testNonFinal turn, the JVM is warmed up by the previous tests, and the common code should yet be optimized.

Easier inlining

Less bytecode translates also to easier and shorter inlining, and so better usage of the resources and better performance.

Embedded devices

Java developers can potentially write code that runs on servers, desktops and small or embedded devices, so making code more efficient at compile time (and not completely relying on the JVM optimizations) can save memory, time and energy on all the runtimes and lead to less concurrency problems and errors.

More efficient memory allocation and garbage collection

If objects have final or immutable fields, their state can't change and the memory they need is more easily estimated when they are created (so this lead to fewer relocations) and need less defensive copies: in a getter I can directly share an immutable object, without creating a defensive copy.

Finally there's another point about future possibilities: when project Valhalla will see the sunlight and "value classes" will be available, having applied immutability to objects' fields will be a significant simpification for those who want to use them, and take advantage of numerous JIT-compiler optimizations that could came out.

A personal note about immutability

If variables, objects' properties and methods' parameters had been immutable by default in Java (like in Rust), the developers would have been forced to write cleaner and better performing code, and explicitly declaring mutable all the objects which can mutate their value would have made developers more conscious about possible errors.

I don't know if for final classes would be the same, because mutable class does not sound that meaningful to me

Upvotes: 7

Samanja Cartagena
Samanja Cartagena

Reputation: 150

I cannot say it is uncommon because as far as I know it is the only way of declaring a constant in java. As a javascript developer, I know how important the keyword constant is. If you are working in production level, and you have values that can never be changed even accidentally by other coders, values such as SSN number or even names. Then you have to use the final keyword to declare variables. Sometimes it can be very troublesome if certain classes can be inherited. Because if many people are working in a team someone can inherit a class, extend it and even make changes to the variables and methods of the parent class. This can be stopped with the keyword final because even static variables can be changed unless the final keyword is used. As far as your question is concerned I do not think the final keyword can affect the performance of the code, but it can definitely prevent human errors by making sure that other team members do not accidentally modify anything that needs to remain constant.

Upvotes: 0

mel3kings
mel3kings

Reputation: 9405

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.

Upvotes: 89

Eugene
Eugene

Reputation: 120848

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.

Upvotes: 27

user13752845
user13752845

Reputation: 56

As mentioned elsewhere, 'final' for a local variable, and to a slightly lesser extent a member variable, is more a matter of style.

'final' is a statement that you intend the variable to not change (i.e., the variable won't vary!). The compiler can then help you out by complaining if you violate your own constraint.

I share the sentiment that Java would have been a better language if identifiers (I'm sorry, I just cannot call a non-varying thing a 'variable') were final by default, and required you to explicitly say that they were variables. But having said that, I don't generally use 'final' on local variables that are initialized and never assigned; it just seems too noisy.

(I do use final on member variables)

Upvotes: 3

Bill K
Bill K

Reputation: 62769

Final (At least for member variables and parameters) is more for humans then it is for the machine.

It's good practice to make variables final wherever possible. I wish Java had made "variables" final by default and had a "Mutable" keyword to allow changes. Immutable classes lead to much better threaded code, and just glancing at a class with "final" in front of each member will quickly show it to be immutable.

Another case--I've been converting a lot of code to use @NonNull/@Nullable annotations (You can say a method parameter must not be null then the IDE can warn you every place you pass a variable that isn't tagged @NonNull--the whole thing spreads to a ridiculous degree). It's much easier to prove a member variable or parameter can't be null when it's tagged final since you know it's not being re-assigned anywhere else.

My suggestion is to get in the habit of applying final for members and parameters by default, It's just a few characters but will nudge you towards improving your coding style if nothing else.

Final for methods or classes is another concept since it disallows a very valid form of reuse and doesn't really tell the reader much. The best use is probably the way they made String and the other intrinsic types final so you could rely on consistent behavior everywhere--That prevented a lot of bugs (although there are times I would have LOVED to extend string.... oh the possibilities)

Upvotes: 2

rustyx
rustyx

Reputation: 85341

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.

Upvotes: 114

user3663845
user3663845

Reputation: 239

Actually, while testing some OpenGL-related code, I found that using the final modifier on a private field can degrade performance. Here is the start of the class I tested:

public class ShaderInput {

    private /* final */ float[] input;
    private /* final */ int[] strides;


    public ShaderInput()
    {
        this.input = new float[10];
        this.strides = new int[] { 0, 4, 8 };
    }


    public ShaderInput x(int stride, float val)
    {
        input[strides[stride] + 0] = val;
        return this;
    }

    // more stuff ...

And this is the method I used to test the performance of various alternatives, amongst which the ShaderInput class:

public static void test4()
{
    int arraySize = 10;
    float[] fb = new float[arraySize];
    for (int i = 0; i < arraySize; i++) {
        fb[i] = random.nextFloat();
    }
    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();
    }
}

After the 3rd iteration, with the VM warmed up, I consistently got these figures without the final key word:

Simple array copy took   : 02.64
System.arrayCopy took    : 03.20
ShaderInput took         : 00.77
Unsafe float array took  : 05.47

With the final keyword:

Simple array copy took   : 02.66
System.arrayCopy took    : 03.20
ShaderInput took         : 02.59
Unsafe float array took  : 06.24

Note the figures for the ShaderInput test.

It didn't matter whether I made the fields public or private.

Incidentally, there are a few more baffling things. The ShaderInput class outperforms all other variants, even with the final keyword. This is remarkable b/c it basically is a class wrapping a float array, while the other tests directly manipulate the array. Have to figure this one out. May have something to do with ShaderInput's fluent interface.

Also System.arrayCopy actually apparently is somewhat slower for small arrays than simply copying elements from one array to the other in a for loop. And using sun.misc.Unsafe (as well as direct java.nio.FloatBuffer, not shown here) performs abysmally.

Upvotes: 2

adityaraj
adityaraj

Reputation: 19

final keyword can be used in five ways in Java.

  1. A class is final
  2. A reference variable is final
  3. A local variable is final
  4. A method is final

A class is final: a class is final means we cannot be extended or inheritance means inheritance is not possible.

Similarly - A object is final: some time we does not modified the internal state of object so in such case we can specify the object is final object.object final means not variable also final.

Once reference variable is made final, it cannot be reassigned to other object. But can change the contents of the object as long as its fields are not final

Upvotes: -4

Jon Skeet
Jon Skeet

Reputation: 1500504

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...

Upvotes: 328

Crozin
Crozin

Reputation: 44376

I'm not an expert but I suppose you should add final keyword to the class or method if it won't be overwritten and leave variables alone. If there will be any way to optimize such things the compiler will do that for you.

Upvotes: 1

sleske
sleske

Reputation: 83609

You are really asking about two (at least) different cases:

  1. final for local variables
  2. final for methods/classes

Jon Skeet has already answered 2). About 1):

I don't think it makes a difference; for local variables, the compiler can deduce whether the variable is final or not (simply by checking whether it is assigned more than once). So if the compiler wanted to optimize variables that are only assigned once, it can do so no matter whether the variable is actually declared final or not.

final might make a difference for protected/public class fields; there it's very difficult for the compiler to find out if the field is being set more than once, as it could happen from a different class (which may not even have been loaded). But even then the JVM could use the technique Jon describes (optimize optimistically, revert if a class is loaded which does change the field).

In summary, I don't see any reason why it should help performance. So this kind of micro-optimization is unlikely to help. You could try benchmarking it to make sure, but I doubt it will make a difference.

Edit:

Actually, according to Timo Westkämper's answer, final can improve performance for class fields in some cases. I stand corrected.

Upvotes: 13

Neowizard
Neowizard

Reputation: 3017

Note: Not a java expert

If I remember my java correctly, there would be very little way to improve performance using the final keyword. I've always known it to exist for "good code" - design and readability.

Upvotes: 6

wmitchell
wmitchell

Reputation: 5735

According to IBM - it doesnt for classes or methods.

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

Upvotes: 38

Related Questions