For和foreach循环-如何最有效地创建它们 [英] For and foreach loops- how to create them most efficiently

查看:87
本文介绍了For和foreach循环-如何最有效地创建它们的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我进行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){
   }

我知道这实际上是两个不同的问题,但是我认为它们足够相似,足以证明我在同一个问题中-如果我错了,请纠正我

解决方案

您可以编译方法并比较它们的字节码以查看差异.

最大的区别是在func1func2之间,其中<​​c0>仅调用size()一次,而func2每次迭代都重新调用size().如果size()没有被缓存(大多数实现都缓存了它),那么重新计算它可能会很昂贵.即使在那种情况下,抖动也可能会优化它,尤其是使用局部变量,因为它可能会意识到列表不会更改.但是,如果列表是暴露的成员,则每次可能需要重新计算大小,因为一个单独的线程可能已经修改了列表,尽管仍然很可能会进行优化以假定大小未更改.

func3fun4之间的唯一区别是func4使用了额外的astoreaload,因为它将列表存储在本地变量中,可以通过抖动对其进行优化. /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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆