2012-09-29 44 views
8

当您需要索引时循环访问数组的最佳方式是什么?Java for循环最佳实践

选项1:

int len = array.length; 
for (int i = 0; i < len; ++i) { 
    array[i] = foo(i); 
} 

选项2:

for (int i = 0; i < array.length; i++) { 
    array[i] = foo(i); 
} 

或者说,它没有关系?还是有更好的方法来做到这一点? 只是为了指出不同之处:在一种情况下,数组的长度作为循环中测试的一部分进行评估,尽管编译器通常应优化它。


其次,是 ++ii++有什么不同吗?如果它是C++,我肯定更喜欢 ++i但我不确定Java。

+3

这些不应该是任何不同。 – 2012-09-29 02:41:53

回答

6

i++ vs ++i在这种特殊情况下无关紧要。虽然C主人会告诉你将array.length存储在一个变量中,但现在的优化编译器在这种情况下只要长度在循环中没有改变就没有必要。如果你真的担心,你可以对两者进行基准测试,但由于.length实际上并不需要遍历整个阵列,所以每次你都可以。

+0

很好的回答!其实也建议总是使用选项1,不是吗? –

+0

选项1到哪个问题?要'我++'vs'++ i'?出于可读性的原因,我更喜欢“i ++”,但我可以明白为什么'++ i'可能是一个更好的默认值,所以'i'的新值可用于在您更改代码并且未注意到后置。 '++ i'对愚蠢的编译器来说也更快,它不会意识到用户不关心表达式具有什么值。 – Dan

+0

不,我的意思是'.length'的选项1。对于'++ i'与'i ++',我认为这只是一个代码风格问题。 –

6

通常这两种方法是等价的。你应该注意到,在

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

foo()在每次迭代之前调用一次(而不是在第一次迭代之前只有一次),所以你可能想也许做这样的事情来考虑这一点对于更复杂的情况

int n = foo(); 
for (int i = 0 ; i < n ; i++) { 
    ... 
} 

这类似于你选项1。所以我会说选项1肯定是两者的安全性,但大多数情况下它不应该使用显着差异。


至于你的第二个问题:++i第一增量的变量,然后检索它的值,i++首先检索值,然后递增。刚刚尝试这两段代码:

int i = 0; 
System.out.println(++i); 
------------------------ 
int i = 0; 
System.out.println(i++); 

的第一印像1但第二打印0。当然,当单独使用++ii++时,没有区别。

+0

我在问题中看不到'i

+0

@BheshGurung这个'foo'函数演示了如何重复评估for-loop条件的rhs,正如我所提到的。当你在rhs上有'array.length'这样的东西时,它没有任何区别。但是当你有'foo'这样的东西时,你应该谨慎一些。 – arshajii

+0

@arshajii我担心foo()在大小()访问的情况下会减慢速度,我跑了一些测试(见最后一个答案)。显然它是一样的。编译器是否在编译时将size()转换为简单的var访问? – Ced

0

对于是否在使用“array.length” for循环: 一般来说,编译器会做一些优化,其结果就相当于在使用一个变量循环

为“我++”和“ ++ i“ 在C++中,++ i更受欢迎,效率更高,但在Java中,它们在这种情况下是等价的。

0

除了arshaji响应,我想知道在循环中使用size()与预先存储循环之间是否有性能优势。我相信结果表明,编译器确实优化了事情,访问列表的长度与访问变量相同(我担心它必须通过函数才会减慢速度)。

这里是它需要为这两个for循环的不同方法的时间:

for(long i = 0 ; i < mylist.size(); i++){} 
VS 
for(long i = 0 ; i < 10_000_000; i++){} 

这里是千万elems的列表结果:

fixed length: 
,162,157,151,157,156,159,157,149,150,170,158,153,152,158,151,151,156,156,151,153 
getSize: 
,164,156,159,154,151,160,162,152,154,152,151,149,168,156,152,150,157,150,156,157 



import java.util.ArrayList; 
import java.util.List; 

public class Main { 

    final static int LENGTH_SAMPLE = 20; 
    final static long LENGTH = 10_000_000; 

    public static void main(String[] args) { 

     List<Long> mylist = new ArrayList<>(); 
     for(long i = 0 ; i < LENGTH; i++){ 
      mylist.add(i); 
     } 
     System.out.println("fixed length:"); 
     for(int i = 0 ; i < LENGTH_SAMPLE; i++){ 
      System.out.printf("," + fixedSize(mylist)); 
     } 
     System.out.println(""); 
     System.out.println("getSize:"); 
     for(int i = 0 ; i < LENGTH_SAMPLE; i++){ 
      System.out.printf("," + fctSize(mylist)); 
     } 
    } 

    private static long fixedSize(List list){ 
     long start = System.currentTimeMillis(); 

     for(long i = 0 ; i < LENGTH; i++){ 
      System.currentTimeMillis(); 
     } 
     return System.currentTimeMillis() - start; 
    } 

    private static long fctSize(List list){ 
     long start = System.currentTimeMillis(); 

     for(long i = 0 ; i < list.size(); i++){ 
      System.currentTimeMillis(); 
     } 
     return System.currentTimeMillis() - start; 
    } 
}