Reputation: 657
Suppose we have a double loop with a large number of iteration, should we define the variable outside the loop for speed up? Just for example:
for(int i=0;i<2000;i++)
for(int j=0;j<1000;j++)
System.out.println(i+j);
Since we initialize j each time when i changes the value, is it better to declare j outside, such as:
for(int i=0;i<2000;i++){
int j=0;
for(j=0;j<1000;j++)
System.out.println(i+j);
}
For myself, I like the first way, it is more readable. However, I am not sure does the second way will speed up the program or not?
Upvotes: 0
Views: 159
Reputation: 4602
There is no point in doing so. Builtin types have no remarkable setup cost.
The thing is different with objects.
You should predeclare Objects outside the loop for performance reasons. I tested this with JDK 1.4, never again since then. Possibly newer JDKs will optimize this away.
for(int i=0;i<2000;i++)
for(int j=0;j<1000;j++)
String x = "Hello " + j;
is remarkably slower than (define outside loop)
String x;
for(int i=0;i<2000;i++)
for(int j=0;j<1000;j++)
x = "Hello " + j;
is remarkably slower than (final in loop)
for(int i=0;i<2000;i++)
for(int j=0;j<1000;j++)
final String x = "Hello " + j;
update: just ran a timing with JDK 7u45, 1000 x 1000 iterations
I have set the code to run the loops more than once and to keep the variables in a result array. Another run will not store the variables outside the loop.
String allocation in loop and no store: Avg 43.5 / NoGC: 39-47
String allocation outside loop and store in array: Avg 98.9 / NoGC: 42-44
String allocation outside loop and no store: Avg 28.25 / NoGC: 27-32
final String allocation in loop and store in array: Avg 98.92 / NoGC: 42-50
The results show, that the declaration of the object takes it's toll. But the real driver is the GC. The effects of declaration inside the loop or outside are small over time, if the value is used outside the loop. Using a final String inside the loop will make no difference. If you do not store outside the loop, the difference is remarkable between the declaration of the variable inside the loop or outside, final, again, makes no difference.
(* When storing all the values, most of the time was lost in GC runs, that is why I added the span of the runs without GC.)
Upvotes: 0
Reputation: 17955
The code generated by Javac is exactly the same, so there cannot be any difference:
Given a "Test.java" file:
public class Test {
public static int a(int[][] v) {
int sum = 0;
int rows = v.length;
int cols = v[0].length; // yes, this fails if v[0] is null
for (int j=0; j<rows; j++) {
for (int i=0; i<cols; i++) {
sum += v[j][i];
}
}
return sum;
}
public static int b(int[][] v) {
int sum = 0;
int rows = v.length;
int cols = v[0].length; // yes, this fails if v[0] is null
int j, i;
for (j=0; j<rows; j++) {
for (i=0; i<cols; i++) {
sum += v[j][i];
}
}
return sum;
}
}
Compile (javac Test.java
) and look at the bytecode (result of javap -c Test
) in the class-file. Here is b
:
public static int b(int[][]);
Code:
0: iconst_0
1: istore_1
2: aload_0
3: arraylength
4: istore_2
5: aload_0
6: iconst_0
7: aaload
8: arraylength
9: istore_3
10: iconst_0
11: istore 4
13: iload 4
15: iload_2
16: if_icmpge 50
19: iconst_0
20: istore 5
22: iload 5
24: iload_3
25: if_icmpge 44
28: iload_1
29: aload_0
30: iload 4
32: aaload
33: iload 5
35: iaload
36: iadd
37: istore_1
38: iinc 5, 1
41: goto 22
44: iinc 4, 1
47: goto 13
50: iload_1
51: ireturn
You get exactly the same byte-code for both a
and b
Upvotes: 1
Reputation: 24464
No, the second form is not better in any way (it won't even compile because you missed the init-section of the for-loop)!
The for statement is built as follows: for (init, expression, update) statement
The init
statement will be executed just ONCE before the loop
starts
The expression
statement will be executed before every iteration of
the loop. Only if it results to true
, the loop will continue.
The update
statement will be executed right after every iteration.
The statement
is the statement that will be executed in every
iteration.
So it's just a short form of:
init;
while (expression) {
statement;
update;
}
As init
will only be executed once, it's no optimization if you put it before the for
loop.
Upvotes: 1