编译器如何处理for循环中的size方法

时间:2013-09-23 20:45:29

标签: java arraylist

以下两个片段中的哪一个更快,假设list是一个ArrayList。

for(int i=0; i<list.size();i++){...}

int count = list.size();
for(int i=0; i<count;i++){...}

此外,优化(如果有的话)是否适用于Android的ArrayAdapter?

int sCount = mAdapter.getCount();

澄清

在for循环中,

每次编译器调用list.size()或者调用它一次并随后使用它。

注意每次调用list.size()实际上都会对项目进行计数。这就是问题的本质。

7 个答案:

答案 0 :(得分:3)

在大多数情况下,速度无法区分。也就是说,如果在循环执行时集合可能正在改变,那么你的两个循环在语义上是不同的。集合的修改可以在循环中(或在循环中调用的代码中)或在同时执行的不同线程中。

专门回答您的“澄清”:是的,每次循环都会调用size方法。

我永远不会写这个循环的“优化”版本,除非我有明确的证据表明优化很重要(并且集合没有改变)。如果您的代码经过如此调整,以至于此类调整可以为您提供可衡量的加速,那么您应该非常高兴。

答案 1 :(得分:2)

你应该问自己一些问题:

  • 我是否有性能问题?
  • 我是否描述了此代码的瓶颈?

如果可以通过YES回答展位问题,那么请尝试双向并分析结果。

事实上,我认为它不会有所作为。

答案 2 :(得分:0)

任何体面的编译器都会将这些编译为完全相同的汇编代码。

答案 3 :(得分:0)

int count = list.size();
for(int i=0; i<count;i++){...}// Is faster

答案 4 :(得分:0)

我猜这些编译成同样的东西,因此速度是一样的。

不确定Android的ArrayAdapter。

答案 5 :(得分:0)

    ArrayList list = new ArrayList();
            for(int i=0; i<1000000;i++){
                list.add("Object added "+i);
            }
            long startTime =System.currentTimeMillis();
            for(int i=0; i<list.size();i++){
                System.out.println(list.get(i));
            }
            long endTime = System.currentTimeMillis();




            int count=list.size();
            long startTime1 =System.currentTimeMillis();
            for(int i=0; i<count;i++){
                System.out.println(list.get(i));
            }
            long endTime1 = System.currentTimeMillis();
            System.out.println("Exe1 time in millis secs"+(endTime-startTime));
            System.out.println("Exe2 time in millis secs"+(endTime1-startTime1));

OutPut 
...........
.............

Object added 999999
Exe1 time in millis secs14131
Exe2 time in millis secs14106

答案 6 :(得分:0)

我认为第二段代码稍快一些。方法调用可能需要将代码加载到内存中,并将数据从方法内存堆栈加载到方法内存堆栈(如第一段代码中所示)。这显然比单个内存访问(第一段代码)慢。但是,如果在循环迭代期间数组大小可能会发生变化,我认为使用第一段代码会更安全。请考虑以下示例:

for(int i=0; i<list.size();i++){
  if list.get(i) == 0 { list.remove(i); i--; }
}    

上面的示例从数组中删除null元素。因此,每次删除元素时,数组大小都会减小。如果你不使用list.size()并忘记适当地更新数组的大小,你将最终得到“索引越界”异常。