考虑以下代码:
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")
调用就足够了吗?
答案 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}},0
,1
以及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
如何运作
int idx = 0
str.split("\\D").length;
idx++
str.split("\\D").length;
idx < str.split("\\D").length()
失败所以每次你的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次。