简体   繁体   English

Java for循环迭代

[英]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? 这部分代码: str.split("\\\\D")将执行多少次? Three times? 三次? Or will the compiler see that as str is declared as final , only one call to str.split("\\\\D") will be enough? 还是编译器会看到将str声明为final ,仅对str.split("\\\\D")一次调用就足够了吗?

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 . 显然,无论str的终结性和split的不变性如何, split都会执行 四次。

JLS 14.14.1.2 states ( Expression here being the middle bit of the for statement): JLS 14.14.1.2状态(此处的Expression for语句的中间位):

Next, a for iteration step is performed, as follows. 接下来,执行for迭代步骤,如下所示。 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 . 这意味着您的具体情况将不会把它一次三次,这实际上把它四次idx分别设置为012 ,并在最后检查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. 拆分方法将被执行3次,以确定长度, 但这无关的事实,串最终还是没有。 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 输出将显示每一轮: index Called

How does for loop works for loop工作原理

  1. Initialization ---> int idx = 0 初始化---> int idx = 0
  2. Condition check ---> str.split("\\\\D").length; 条件检查---> str.split("\\\\D").length;
  3. Execute Loop body 执行循环体
  4. Increment index idx++ 增量索引idx++
  5. check condition str.split("\\\\D").length; 检查条件str.split("\\\\D").length;
  6. Execute Loop body 执行循环体
  7. Repeat steps 4-6 till idx < str.split("\\\\D").length() fails 重复步骤4-6,直到idx < str.split("\\\\D").length()失败

So every time your idx < str.split("\\\\D").length() will get executed. 因此,每次您的idx < str.split("\\\\D").length()将被执行。 I would say it will get execute three times for condition match and one last for condition fail. 我会说条件匹配将执行3次,条件失败则最后执行一次。

There's a 100% sure way to see if a compiler optimizes something - look at the compilation result. 有一种100%确定的方法可以查看编译器是否进行了某些优化-查看编译结果。 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). 我已经在响应中包含了字节码,并且我认为这很明显-无论哪种最终关键字,split方法都会在第一种情况下多次执行(invoke virtual行是split方法调用,您可以了解什么是转到goto语句)。

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' 随时在所需的环境上重新测试(您可以使用“ 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. str.split(“ \\ D”)不会分割您的str字符串,它返回String []数组的新实例。 Answer is 3 times str.split("\\D") will be executed. 答案是执行str.split(“ \\ D”)3次。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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