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.