Java:什么是在循环中拆分或之前拆分更快
Goolge提出了很多比较,但不是我想要的: 如果我想遍历拆分的字符串,有什么更好的方法Java:什么是在循环中拆分或之前拆分更快,java,performance,loops,split,Java,Performance,Loops,Split,Goolge提出了很多比较,但不是我想要的: 如果我想遍历拆分的字符串,有什么更好的方法 String[] flagArr = flags.split(";"); for (String f: flagArr) { // some stuff } 或 对于第二段代码,我想知道编译器是否足够聪明,可以只拆分一次,我认为编译器会对此进行优化。这可能取决于您选择的Java提供商sun、ibm等。。。但这是如此简单,如果不是每个编译器都这么做,我会感到惊讶 也许可以创建一个非常大的标志字符串并
String[] flagArr = flags.split(";");
for (String f: flagArr) {
// some stuff
}
或
对于第二段代码,我想知道编译器是否足够聪明,可以只拆分一次,我认为编译器会对此进行优化。这可能取决于您选择的Java提供商sun、ibm等。。。但这是如此简单,如果不是每个编译器都这么做,我会感到惊讶
也许可以创建一个非常大的标志字符串并进行一些简单的性能测试
但是,既然这很容易,为什么不做你的第一个选择……这一点都不重要。不要浪费时间进行此类优化
编辑:如果您想关心这件事,您可以使用第二个选项,因为带有拆分的数组将只存在于for循环范围内。我很确定拆分将只进行一次。在内部,这段代码将被翻译成一个带有迭代器的循环,因此编译器将执行一次拆分,创建结果集合,然后在该集合上创建迭代器
如果要重复拆分,迭代器将不会指向正确的位置。您可以检查生成的字节码,但我非常确定它们都会执行相同的操作。为什么第二个会有什么不同 编辑:正如您所看到的,两种方法都只调用split一次 第一个字节码:
public class javatesting.JavaTesting extends java.lang.Object{
public javatesting.JavaTesting();
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: astore_1
3: aload_1
4: ldc #3; //String ;
6: invokevirtual #4; //Method java/lang/String.split:(Ljava/lang/String;)
[Ljava/lang/String;
9: astore_2
10: aload_2
11: astore_3
12: aload_3
13: arraylength
14: istore 4
16: iconst_0
17: istore 5
19: iload 5
21: iload 4
23: if_icmpge 41
26: aload_3
27: iload 5
29: aaload
30: astore 6
32: aconst_null
33: astore 6
35: iinc 5, 1
38: goto 19
41: return
}
第二个字节码是:
public class javatesting.JavaTesting extends java.lang.Object{
public javatesting.JavaTesting();
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: astore_1
3: aload_1
4: ldc #3; //String ;
6: invokevirtual #4; //Method java/lang/String.split:(Ljava/lang/String;)
[Ljava/lang/String;
9: astore_2
10: aload_2
11: arraylength
12: istore_3
13: iconst_0
14: istore 4
16: iload 4
18: iload_3
19: if_icmpge 37
22: aload_2
23: iload 4
25: aaload
26: astore 5
28: aconst_null
29: astore 5
31: iinc 4, 1
34: goto 16
37: return
}
试试这个:
public double calculateRunTime()
{
long startTime = System.currentTimeMillis();
split();
long endTime = System.currentTimeMillis();
return endTime - startTime;
}
如果您真的想看到字节码中的差异,请使用javap-c。使用Eclipse编译器编译,源代码中带有局部变量的第一个版本给出了以下内容:
public static void test(java.lang.String);
Code:
0: aload_0
1: ldc #16; //String ;
3: invokevirtual #18; //Method java/lang/String.split:(Ljava/lang/String;)[Ljava/lang/String;
6: astore_1
7: aload_1
8: dup
9: astore 5
11: arraylength
12: istore 4
14: iconst_0
15: istore_3
16: goto 27
19: aload 5
21: iload_3
22: aaload
23: astore_2
24: iinc 3, 1
27: iload_3
28: iload 4
30: if_icmplt 19
33: return
}
第二点:
public static void test(java.lang.String);
Code:
0: aload_0
1: ldc #16; //String ;
3: invokevirtual #18; //Method java/lang/String.split:(Ljava/lang/String;)[Ljava/lang/String;
6: dup
7: astore 4
9: arraylength
10: istore_3
11: iconst_0
12: istore_2
13: goto 24
16: aload 4
18: iload_2
19: aaload
20: astore_1
21: iinc 2, 1
24: iload_2
25: iload_3
26: if_icmplt 16
29: return
}
如您所见,如果您能阅读本文,第一个变量确实在开始时使用了一个额外的局部变量槽astore_1/aload_1。然而,a即使字节码被解释,其开销也可以忽略——它只是复制引用,b任何JIT编译器都将能够对此进行优化,无论您是否事先进行了一些静态字节码优化:局部变量1以后永远不会被使用
源代码中的局部变量主要用于清晰性和能够重用中间结果。基本上,没有显式局部变量的第二个变量将不允许您在方法中甚至直接在循环中重复使用拆分的结果,而您可以在代码中命名局部变量
对于第二段代码,我想知道编译器是否足够聪明
只做一次分割
这两个方法之间的唯一区别是在源代码中显式声明局部变量
在这两种情况下,对于字符串f:flags.split;{}是语法糖,但两个局部变量都不可访问,这两个变量等价于:
int _hidden_i = 0;
for (String[] _hidden_arr=flags.split(";"); _hidden_i<_hidden_arr.length; _hidden_i++){
String f = _hidden_arr[_hidden_i];
// some stuff
}
在为;;表示法,第一部分始终执行一次。第二个表达式总是在进入循环块之前执行,以测试是否运行它。最后一个总是在运行循环块后执行,除非使用break
通常,您希望避免在第二部分中可能很重的方法调用,尤其是在结果总是相同的情况下。为什么不自己运行一个简短的基准测试?只要用相同的字符串运行这两个版本n次,并且有足够大的n,并跟踪您感兴趣的时间或内存使用情况。但是后来我发现问一个问题是更好的选择,因为更多地了解Java的内部功能可以提高我的编程技能。另外,其他人可能有相同的问题。您可以调试这两个版本。那就是找出后台发生了什么。我完全不同意。以另一种方式做某事可能会导致巨大的性能差异。例如,查看此链接:是的,有时它很重要,有时它不重要。在这种情况下,它不是,这是我的观点。谢谢你-非常好的背景知识。谢谢-准确地回答了问题。这就是我要找的。
int _hidden_i = 0;
for (String[] _hidden_arr=flags.split(";"); _hidden_i<_hidden_arr.length; _hidden_i++){
String f = _hidden_arr[_hidden_i];
// some stuff
}
for (var i = 0; i < flags.split(";").length; i++) {
String f = flags.split(";")[i];
}