Does use of final keyword in Java improve the performance?

前端 未结 13 1076
粉色の甜心
粉色の甜心 2020-11-22 08:42

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


        
相关标签:
13条回答
  • 2020-11-22 08:53

    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.

    0 讨论(0)
  • 2020-11-22 08:54

    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.

    0 讨论(0)
  • 2020-11-22 09:00

    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.

    0 讨论(0)
  • 2020-11-22 09:01

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

    0 讨论(0)
  • 2020-11-22 09:01

    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.

    0 讨论(0)
  • 2020-11-22 09:05

    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.

    0 讨论(0)
提交回复
热议问题