简体   繁体   中英

Java for-loop iteration

Consider the following piece of code:

final String str = "1-2-3";

for (int idx = 0; idx < str.split("\\D").length; idx++) {
    // do something
}

How many times will this portion of code: str.split("\\\\D") be executed? Three times? Or will the compiler see that as str is declared as final , only one call to str.split("\\\\D") will be enough?

This might be interesting to you. For this code:

class Foo {
  public static void main(String args[]) {
    final String str = "1-2-3";

    for (int idx = 0; idx < str.split("\\D").length; idx++) {
    }
  }
}

the bytecode is:

Compiled from "Foo.java"
class Foo {
  Foo();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return        

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0      
       1: istore_2      
       2: iload_2       
       3: ldc           #2                  // String 1-2-3
       5: ldc           #3                  // String \D
       7: invokevirtual #4                  // Method java/lang/String.split:(Ljava/lang/String;)[Ljava/lang/String;
      10: arraylength   
      11: if_icmpge     20
      14: iinc          2, 1
      17: goto          2
      20: return        
}

It is clear that split is executed three FOUR times, regardless of the finality of str , and of invariance of split .

JLS 14.14.1.2 states ( Expression here being the middle bit of the for statement):

Next, a for iteration step is performed, as follows. If the Expression is present, it is evaluated.

That means it does it on each iteration step, there is no leeway there in the specification for optimisation.

You can see something similar with the following code:

class Test {
    public static int getSeven () {
        System.out.println ("called getSeven()");
        return 7;
    }
    public static void main (String[] args){
        for (int i = 1; i <= getSeven(); i++) {
            System.out.println ("i = " + i);
        }
    }
}

When you run that, you get:

called getSeven()
i = 1
called getSeven()
i = 2
called getSeven()
i = 3
called getSeven()
i = 4
called getSeven()
i = 5
called getSeven()
i = 6
called getSeven()
i = 7
called getSeven()

showing that the function is called each time through the loop (including the exit condition).

That means your particular case won't call it once or three times, it will actually call it four times, with idx set respectively to 0 , 1 , 2 and the final check at 3 .

EDIT

The split method will be executed 3 times to determine the length, BUT this has nothing to do with the fact that the string is final or not. It would be execute the same even if the strign was not final.

See this example :

/* package whatever; // don't place package name! */

import java.util.*;
import java.lang.*;
import java.io.*;

/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
    public static void main (String[] args) throws java.lang.Exception
    {
        String g = "bla bla";
        for (int i = 0; i < index(g); i++)
        {
            System.out.println("Round");
        }
    }

    public static int index(String input)
    {
        System.out.println("index Called");
        return input.length();
    }
}

The output will show for each round: index Called

How does for loop works

  1. Initialization ---> int idx = 0
  2. Condition check ---> str.split("\\\\D").length;
  3. Execute Loop body
  4. Increment index idx++
  5. check condition str.split("\\\\D").length;
  6. Execute Loop body
  7. Repeat steps 4-6 till idx < str.split("\\\\D").length() fails

So every time your idx < str.split("\\\\D").length() will get executed. I would say it will get execute three times for condition match and one last for condition fail.

There's a 100% sure way to see if a compiler optimizes something - look at the compilation result. I've included the byte code in the response and I think it's pretty obvious - the split method will be executed multiple times in the first case regardless of the final keyword (the invoke virtual line is the split method call, you can understand what is looped by the goto statement).

Different compilers MAY behave in a different way, though. Feel free to retest this on your desired environment (you can view bytecode with 'javap -c classname'

public class gti {
    public static void main ( String[] args ) {
        final String str = "1-2-3";

        for (int idx = 0; idx < str.split("\\D").length; idx++) {
            // do something
        }
    }
}

results in:

public class gti {
  public gti();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0
       1: istore_2
       2: iload_2
       3: ldc           #2                  // String 1-2-3
       5: ldc           #3                  // String \D
       7: invokevirtual #4                  // Method java/lang/String.split:(Ljava/lang/String;)[Ljava/lang/String;
      10: arraylength
      11: if_icmpge     20
      14: iinc          2, 1
      17: goto          2
      20: return
}

while

public class gti {
    public static void main ( String[] args ) {
        final String str = "1-2-3";
        int length = str.split("\\D").length;
        for (int idx = 0; idx < length; idx++) {
            // do something
        }
    }
}

results in:

public class gti {
  public gti();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String 1-2-3
       2: ldc           #3                  // String \D
       4: invokevirtual #4                  // Method java/lang/String.split:(Ljava/lang/String;)[Ljava/lang/String;
       7: arraylength
       8: istore_2
       9: iconst_0
      10: istore_3
      11: iload_3
      12: iload_2
      13: if_icmpge     22
      16: iinc          3, 1
      19: goto          11
      22: return
}

str.split("\\D") will not split your str string it returns new instance of String[] array. Answer is 3 times str.split("\\D") will be executed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM