【问题标题】:For and foreach loops- how to create them most efficientlyFor 和 foreach 循环 - 如何最有效地创建它们
【发布时间】:2019-12-16 06:26:48
【问题描述】:

当我制作 for 循环或 foreach 循环时,以这两种不同的方式执行它们之间是否存在效率差异?

for 循环:

 int x = myArray.size();

 for(int ind = 0; ind<x; ind++){
 //do stuff
 }

 for(int ind = 0; ind<myArray.size(); ind++){
 //do stuff

 }

foreach 循环:

   for(String str: myClass.getStringList()){}

   ArrayList<String>list = myClass.getStringList();

   for(String str: list){
   }

我知道这确实是两个不同的问题,但我认为它们足够相似,足以证明存在同一个问题是合理的——如果我错了,请纠正我

【问题讨论】:

  • 这些是微优化。在上述示例中,首选方法的动机应该是可读性而不是性能。
  • 每一个都做一百万次,测量,取平均值,比较。
  • for 存在差异(可测量?),因为每次迭代都会调用 size 方法; for-each循环几乎一样,getStringList只被调用一次(14.14.2. The enhanced for statement

标签: java for-loop foreach


【解决方案1】:

以下情况更好,因为它只计算一次数组的大小,并用于检查 for 内部。

int x = myArray.size();

 for(int ind = 0; ind<x; ind++){
 //do stuff
 }

与上述情况相比,以下情况不是一个有效的情况,因为它在每次 for 循环运行时计算数组的大小。

for(int ind = 0; ind<myArray.size(); ind++){
 //do stuff

 }

对于像

这样的泛型
List<String> list = new ArrayList<>();

总是建议像你已经提到的那样使用。

for(String str: list){
   }

【讨论】:

  • 你确定这是真的吗? arraylist.size() 我认为是不变的。
  • @Sambit 这个链接是关于 Javascript 的。
  • @Sedrick 我相信你是对的,不是每个循环都计算,所以他的措辞是错误的,但我相信它会稍微快一些,因为不是每个循环都调用方法是时候取回该值,而是取回一个本地值,但这对于优化来说是极小的。虽然如果您在循环中再次使用长度,那么它很有用。
  • @Sedrick 常量是private static final int size,不是吗?它不是。
【解决方案2】:

如果 .size().getStringList() 方法是常量,则它们之间没有区别。如果每次调用都不需要计算,我们说它们是常量(例如,如果 say 存储为整数而不是每次都计算列表的所有元素)

但就像建议一样:如果性能不是当前要求,那就算了。如果代码不是概念证明,请始终优先考虑易用性。

【讨论】:

    【解决方案3】:

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

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

    func3fun4 之间的唯一区别是func4 使用了额外的astoreaload,因为它将列表存储在局部变量中,这可能会被抖动优化掉。

    最终,测试效率的最佳方法是衡量它。


    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
    

    【讨论】:

      猜你喜欢
      • 2015-07-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-14
      • 2017-06-15
      • 1970-01-01
      相关资源
      最近更新 更多