Impact Of Local Variable Declaration Location
Does the location of a local variable's declaration result in performance changes of a method? For example, will a String
variable, s
, declared outside of a loop exhibit "better" performance than when declared inside a loop? In Java, looking at a class' bytecode explains, irrefutably, why the answer is "no".
The Source
The following example demonstrates the setup: declaration of variable, s
, both inside and outside a loop. All developers should agree that the methods below, inner()
and outer()
, perform the same work: loop 10 times and write the counter to a local String
variable:
public final class Test { public final void inner() { for(int i = 0; i < 10; i++) { final String s = Integer.toString(i); } } public final void outer() { int i; String s; for(i = 0; i < 10; i++) { s = Integer.toString(i); } } }
In truth, the above methods are theoretically useless: Integer.toString()
shouldn't have side effects and the two methods may thus be eliminated. Further, the code formatting of outer()
is slightly irregular and inconsistent with inner()
; however, I have done this for demonstrative purposes.
The Bytecode
The following block shows the bytecode, as generated by javap
, for both methods:
public final void inner(); Code: 0: iconst_0 1: istore_1 2: iload_1 3: bipush 10 5: if_icmpge 19 8: iload_1 9: invokestatic #2 // Method java/lang/Integer.toString:(I)Ljava/lang/String; 12: astore_2 13: iinc 1, 1 16: goto 2 19: return LocalVariableTable: Start Length Slot Name Signature 13 0 2 s Ljava/lang/String; 2 17 1 i I 0 20 0 this LTest; public final void outer(); Code: 0: iconst_0 1: istore_1 2: iload_1 3: bipush 10 5: if_icmpge 19 8: iload_1 9: invokestatic #2 // Method java/lang/Integer.toString:(I)Ljava/lang/String; 12: astore_2 13: iinc 1, 1 16: goto 2 19: return LocalVariableTable: Start Length Slot Name Signature 13 6 2 s Ljava/lang/String; 0 20 0 this LTest; 2 18 1 i I
Notice how the bytecode for inner()
and outer()
is identical: s
is stored in slot 2 (index 12) of the local variable table and i
in slot 1 (index 1). Importantly, this demonstrates that local variables are not naïvely interpreted on a per-line basis but are provisioned during bytecode compilation. This means there cannot be, nor is there, any reasonable difference in performance due to the location of a declaration of a local variable. For interested readers, the JVM documentation provides excellent insight into local variables.
For some reason, this question remains a hot topic on numerous Internet forums. I feel the need to point out this bytecode is not a special case for String
types, as the JVM operates on only 2 types: reference
and primitive
. In this case, as identified by the astore
operation, s
is a reference
type to a heap-bound object instance. Specifically, s
is not a mystical JVM string
type. All objects, complex or not, are handled in the exact same way: as reference
types.
Considerations
In a non-technical way, I argue a variable should be constrained to the smallest scope possible. Keeping a variable hidden when out of scope communicates to other developers, without out-of-band comments and documentation, your pre-conditions and post-conditions of a code block. In addition, using constants (final
) instead of variables further increases such understanding and communication. In any case, I strongly urge fellow developers to use the smallest possible scope for variables or constants, favouring constants whenever possible.