For和foreach循环-如何最有效地创建它们 [英] For and foreach loops- how to create them most efficiently
问题描述
当我进行for循环或foreach循环时,以这两种不同方式进行操作之间在效率上有区别吗?
对于for循环:
int x = myArray.size();
for(int ind = 0; ind<x; ind++){
//do stuff
}
vs
for(int ind = 0; ind<myArray.size(); ind++){
//do stuff
}
for foreach循环:
for(String str: myClass.getStringList()){}
vs
ArrayList<String>list = myClass.getStringList();
for(String str: list){
}
我知道这实际上是两个不同的问题,但是我认为它们足够相似,足以证明我在同一个问题中-如果我错了,请纠正我
您可以编译方法并比较它们的字节码以查看差异.
最大的区别是在func1
和func2
之间,其中<c0>仅调用size()
一次,而func2
每次迭代都重新调用size()
.如果size()
没有被缓存(大多数实现都缓存了它),那么重新计算它可能会很昂贵.即使在那种情况下,抖动也可能会优化它,尤其是使用局部变量,因为它可能会意识到列表不会更改.但是,如果列表是暴露的成员,则每次可能需要重新计算大小,因为一个单独的线程可能已经修改了列表,尽管仍然很可能会进行优化以假定大小未更改.
func3
和fun4
之间的唯一区别是func4
使用了额外的astore
和aload
,因为它将列表存储在本地变量中,可以通过抖动对其进行优化. /p>
最终,测试效率的最佳方法是对其进行测量.
private void func1() {
ArrayList<String> list = new ArrayList<>();
int x = list.size();
for (int i = 0; i < x; i++)
System.out.println(list.get(i));
}
private void func2() {
ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < list.size(); i++)
System.out.println(list.get(i));
}
private void func3() {
for (String str : new ArrayList<String>())
System.out.println(str);
}
private void func4() {
ArrayList<String> list = new ArrayList<>();
for (String str : list)
System.out.println(str);
}
private void func1();
... storing the list ...
8 aload_1 [list]
9 invokevirtual java.util.ArrayList.size() : int [18] // compute list.size()
12 istore_2 [x] // store list.size()
13 iconst_0
14 istore_3 [i]
15 goto 35
... print ...
32 iinc 3 1 [i] // i++
35 iload_3 [i] // load i
36 iload_2 [x] // load the already computed list.size()
37 if_icmplt 18 // if i < list.size() goto 18
40 return
private void func2();
... storing the list ...
8 iconst_0
9 istore_2 [i]
10 goto 30
... print ...
27 iinc 2 1 [i] // i++
30 iload_2 [i] // load i
31 aload_1 [list] // load the list
32 invokevirtual java.util.ArrayList.size() : int [18] // compute list.size()
35 if_icmplt 13 // if i < list.size() goto 13
38 return
private void func3();
... storing the list ...
7 invokevirtual java.util.ArrayList.iterator() : java.util.Iterator [50]
10 astore_2
11 goto 31
14 aload_2
15 invokeinterface java.util.Iterator.next() : java.lang.Object [54] [nargs: 1]
... print ...
31 aload_2
32 invokeinterface java.util.Iterator.hasNext() : boolean [60] [nargs: 1]
37 ifne 14
40 return
private void func4();
... storing the list ...
7 astore_1 [list] // these are the only extra operations
8 aload_1 [list] // to store the list in a local variable
9 invokevirtual java.util.ArrayList.iterator() : java.util.Iterator [50]
12 astore_3
13 goto 33
16 aload_3
17 invokeinterface java.util.Iterator.next() : java.lang.Object [54] [nargs: 1]
... print ...
33 aload_3
34 invokeinterface java.util.Iterator.hasNext() : boolean [60] [nargs: 1]
39 ifne 16
42 return
When I'm making a for loop or a foreach loop, is there an efficiency difference between doing them in these 2 different ways?
For a for loop:
int x = myArray.size();
for(int ind = 0; ind<x; ind++){
//do stuff
}
vs
for(int ind = 0; ind<myArray.size(); ind++){
//do stuff
}
for a foreach loop:
for(String str: myClass.getStringList()){}
vs
ArrayList<String>list = myClass.getStringList();
for(String str: list){
}
I know this is really two different questions but i think they're similar enough to justify being in the same question- correct me if I'm wrong
You can compile the methods and compare their bytecode to see the differences.
The biggest difference is between func1
and func2
where func1
only calls size()
once, whereas func2
re-calls size()
for every iteration. If size()
is not cached (most implementations do cache it) then it could be costly to re-compute it. Even in that case the jitter can probably optimize it, especially with a local variable, since it might realize that the list does not change. But if the list were an exposed member then it might need to re-compute the size each time since a separate thread could have modified the list, though it's still very likely to be optimized to assume that the size has not changed.
The only difference between func3
and fun4
is that func4
uses an extra astore
and aload
since it's storing the list in a local variable, which can probably be optimized away by the jitter.
Ultimately the best way to test efficiency is to measure it.
private void func1() {
ArrayList<String> list = new ArrayList<>();
int x = list.size();
for (int i = 0; i < x; i++)
System.out.println(list.get(i));
}
private void func2() {
ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < list.size(); i++)
System.out.println(list.get(i));
}
private void func3() {
for (String str : new ArrayList<String>())
System.out.println(str);
}
private void func4() {
ArrayList<String> list = new ArrayList<>();
for (String str : list)
System.out.println(str);
}
private void func1();
... storing the list ...
8 aload_1 [list]
9 invokevirtual java.util.ArrayList.size() : int [18] // compute list.size()
12 istore_2 [x] // store list.size()
13 iconst_0
14 istore_3 [i]
15 goto 35
... print ...
32 iinc 3 1 [i] // i++
35 iload_3 [i] // load i
36 iload_2 [x] // load the already computed list.size()
37 if_icmplt 18 // if i < list.size() goto 18
40 return
private void func2();
... storing the list ...
8 iconst_0
9 istore_2 [i]
10 goto 30
... print ...
27 iinc 2 1 [i] // i++
30 iload_2 [i] // load i
31 aload_1 [list] // load the list
32 invokevirtual java.util.ArrayList.size() : int [18] // compute list.size()
35 if_icmplt 13 // if i < list.size() goto 13
38 return
private void func3();
... storing the list ...
7 invokevirtual java.util.ArrayList.iterator() : java.util.Iterator [50]
10 astore_2
11 goto 31
14 aload_2
15 invokeinterface java.util.Iterator.next() : java.lang.Object [54] [nargs: 1]
... print ...
31 aload_2
32 invokeinterface java.util.Iterator.hasNext() : boolean [60] [nargs: 1]
37 ifne 14
40 return
private void func4();
... storing the list ...
7 astore_1 [list] // these are the only extra operations
8 aload_1 [list] // to store the list in a local variable
9 invokevirtual java.util.ArrayList.iterator() : java.util.Iterator [50]
12 astore_3
13 goto 33
16 aload_3
17 invokeinterface java.util.Iterator.next() : java.lang.Object [54] [nargs: 1]
... print ...
33 aload_3
34 invokeinterface java.util.Iterator.hasNext() : boolean [60] [nargs: 1]
39 ifne 16
42 return
这篇关于For和foreach循环-如何最有效地创建它们的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!