creating final variables inside a loop
is this allowed in java:
for(int i=0;i<5;i++){
final int myFinalVariable = i;
}
The keyword of my question is final
. Is it allowed to do a final variable that changes with every run of the loop? I was wondering this because final says that you can't change the value of the variable (calling only myFinalVariable = i
), but i'm redefining the whole variable with final int
.
Are they two completely different variables just with the same name - with the variable from the previous run of the loop already heading down the road to the garbage collector?
Yes, it is allowed. The final
keyword means that you can't change the value of the variable within its scope. For your loop example, you can think of the variable going out of scope at the bottom of the loop, then coming back into scope with a new value at the top of the loop. Assigning to the variable within the loop won't work.
You are right, for each iteration in the loop, you are creating a new variable. The variables do share the same name, but that's fine because they are not in the same scope. Next example would not work:
final int myFinalVariable = 0;
for(int i=0;i<5;i++){
myFinalVariable = i;
}
A variable is just a location on the stack. Try and keep your variables with as small a scope as possible and try to make them final. However scope and final are just source code things... from a code generation/VM point of view they don't really matter at all.
In your specific example, using "int" no garbage is created. However if it were objects being created then for both cases the amount of garbage and when the garbage would be eligible for cleanup would be identical.
Take the following code:
public class X
{
public static void main(final String[] argv)
{
foo();
bar();
}
private static void foo()
{
for(int i=0;i<5;i++)
{
final int myFinalVariable = i;
}
}
private static void bar()
{
for(int i=0;i<5;i++)
{
int myFinalVariable = i;
}
}
}
The compiler produces identical bytecode for each method:
public class X extends java.lang.Object{
public X();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: invokestatic #2; //Method foo:()V
3: invokestatic #3; //Method bar:()V
6: return
private static void foo();
Code:
0: iconst_0
1: istore_0
2: iload_0
3: iconst_5
4: if_icmpge 15
7: iload_0
8: istore_1
9: iinc 0, 1
12: goto 2
15: return
private static void bar();
Code:
0: iconst_0
1: istore_0
2: iload_0
3: iconst_5
4: if_icmpge 15
7: iload_0
8: istore_1
9: iinc 0, 1
12: goto 2
15: return
}
Adding another method that declares the variable outside the loop give you slightly different bytecode due to the order that the variables are declared). Note that this version the variable cannot be made final. This last version is not the best way (the final variable inside the loop is the best if you can do it):
private static void car()
{
int myFinalVariable;
for(int i=0;i<5;i++)
{
myFinalVariable = i;
}
}
private static void car();
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iconst_5
4: if_icmpge 15
7: iload_1
8: istore_0
9: iinc 1, 1
12: goto 2
15: return
}