Java for循环迭代

时间:2013-09-05 08:20:59

标签: java for-loop iterator

考虑以下代码:

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

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

此部分代码执行多少次:str.split("\\D")?三次?或者编译器会看到str被声明为final,只有一次str.split("\\D")调用就足够了吗?

6 个答案:

答案 0 :(得分:6)

这对你来说可能很有意思。对于此代码:

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

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

字节码是:

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        
}

很明显split执行三次四次,无论str的终结性和split的不变性。

答案 1 :(得分:3)

JLS 14.14.1.2声明(Expression这里是for语句的中间位):

  

接下来,执行迭代步骤,如下所述。如果表达式存在,将对其进行评估。

这意味着它在每个迭代步骤中完成,在优化规范中没有余地。

您可以通过以下代码查看类似内容:

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);
        }
    }
}

当你运行它时,你得到:

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()

显示该函数在循环中被称为每个时间(包括退出条件)。

这意味着您的特定情况不会在三次调用它,它实际上会将其称为四次次,idx分别设置为{ {1}},01以及2的最终检查。

答案 2 :(得分:1)

修改

拆分方法将执行3次以确定长度, BUT 这与字符串是最终的事实无关。即使strign不是最终的,它也会执行相同的操作。

请参阅此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();
    }
}

每一轮都会显示输出: index Called

答案 3 :(得分:1)

for loop如何运作

  1. 初始化---&gt; int idx = 0
  2. 条件检查---&gt; str.split("\\D").length;
  3. 执行循环体
  4. 增量索引idx++
  5. 检查条件str.split("\\D").length;
  6. 执行循环体
  7. 重复步骤4-6直到idx < str.split("\\D").length()失败
  8. 所以每次你的idx < str.split("\\D").length()都会被执行。 我会说它会在条件匹配时执行三次,而在条件失败时会执行一次。

答案 4 :(得分:1)

有100%可靠的方法来查看编译器是否优化了某些东西 - 查看编译结果。我在响应中包含了字节代码,我认为很明显 - 在第一种情况下,split方法将被执行多次,而不管final关键字(调用虚拟行是split方法调用,你可以理解什么是循环使用goto语句。)

但是,不同的编译器可能以不同的方式运行。 随意在您想要的环境中重新测试它(您可以使用'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
        }
    }
}

结果:

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
}

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
        }
    }
}

结果:

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
}

答案 5 :(得分:0)

str.split(“\ D”)不会拆分你的str字符串,它会返回String []数组的新实例。 答案是str.split(“\ D”)将被执行3次。