ohmygoddess
ohmygoddess

Reputation: 657

define variable inside vs outside in Java?

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

Answers (3)

thst
thst

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 store in array: Avg 109.49 / NoGC: 47-49 (*)
  • 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

  • final String allocation in loop and no store: Avg 28.31 / NoGC: 27-34

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

tucuxi
tucuxi

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

isnot2bad
isnot2bad

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

Related Questions