Is there a performance difference between a for loop and a for-each loop?

前端 未结 16 1266
清歌不尽
清歌不尽 2020-11-22 10:38

What, if any, is the performance difference between the following two loops?

for (Object o: objectArrayList) {
    o.DoSomething();
}

and <

相关标签:
16条回答
  • Here is a brief analysis of the difference put out by the Android development team:

    https://www.youtube.com/watch?v=MZOf3pOAM6A

    The result is that there is a difference, and in very restrained environments with very large lists it could be a noticeable difference. In their testing, the for each loop took twice as long. However, their testing was over an arraylist of 400,000 integers. The actual difference per element in the array was 6 microseconds. I haven't tested and they didn't say, but I would expect the difference to be slightly larger using objects rather than primitives, but even still unless you are building library code where you have no idea the scale of what you will be asked to iterate over, I think the difference is not worth stressing about.

    0 讨论(0)
  • 2020-11-22 11:08

    Accepted answer answers the question, apart from the exceptional case of ArrayList...

    Since most developers rely on ArrayList(atleast I believe so)

    So I am obligated to add the correct answer here.

    Straight from the developer documentation:-

    The enhanced for loop (also sometimes known as "for-each" loop) can be used for collections that implement the Iterable interface and for arrays. With collections, an iterator is allocated to make interface calls to hasNext() and next(). With an ArrayList, a hand-written counted loop is about 3x faster (with or without JIT), but for other collections the enhanced for loop syntax will be exactly equivalent to explicit iterator usage.

    There are several alternatives for iterating through an array:

    static class Foo {
        int mSplat;
    }
    
    Foo[] mArray = ...
    
    public void zero() {
        int sum = 0;
        for (int i = 0; i < mArray.length; ++i) {
            sum += mArray[i].mSplat;
        }
    }
    
    public void one() {
        int sum = 0;
        Foo[] localArray = mArray;
        int len = localArray.length;
    
        for (int i = 0; i < len; ++i) {
            sum += localArray[i].mSplat;
        }
    }
    
    public void two() {
        int sum = 0;
        for (Foo a : mArray) {
            sum += a.mSplat;
        }
    }
    

    zero() is slowest, because the JIT can't yet optimize away the cost of getting the array length once for every iteration through the loop.

    one() is faster. It pulls everything out into local variables, avoiding the lookups. Only the array length offers a performance benefit.

    two() is fastest for devices without a JIT, and indistinguishable from one() for devices with a JIT. It uses the enhanced for loop syntax introduced in version 1.5 of the Java programming language.

    So, you should use the enhanced for loop by default, but consider a hand-written counted loop for performance-critical ArrayList iteration.

    0 讨论(0)
  • 2020-11-22 11:10
    1. for(Object o: objectArrayList){
        o.DoSomthing();
    }
    and
    
    2. for(int i=0; i<objectArrayList.size(); i++){
        objectArrayList.get(i).DoSomthing();
    }
    

    Both does the same but for easy and safe programming use for-each, there are possibilities for error prone in 2nd way of using.

    0 讨论(0)
  • 2020-11-22 11:11

    It's weird that no one has mentioned the obvious - foreach allocates memory (in the form of an iterator), whereas a normal for loop does not allocate any memory. For games on Android, this is a problem, because it means that the garbage collector will run periodically. In a game you don't want the garbage collector to run... EVER. So don't use foreach loops in your draw (or render) method.

    0 讨论(0)
  • 2020-11-22 11:16

    Well, performance impact is mostly insignificant, but isn't zero. If you look at JavaDoc of RandomAccess interface:

    As a rule of thumb, a List implementation should implement this interface if, for typical instances of the class, this loop:

    for (int i=0, n=list.size(); i < n; i++)
        list.get(i);
    

    runs faster than this loop:

    for (Iterator i=list.iterator(); i.hasNext();)
          i.next();
    

    And for-each loop is using version with iterator, so for ArrayList for example, for-each loop isn't fastest.

    0 讨论(0)
  • 2020-11-22 11:16

    There appears to be a difference unfortunately.

    If you look at the generated bytes code for both kinds of loops, they are different.

    Here is an example from the Log4j source code.

    In /log4j-api/src/main/java/org/apache/logging/log4j/MarkerManager.java we have a static inner class called Log4jMarker which defines:

        /*
         * Called from add while synchronized.
         */
        private static boolean contains(final Marker parent, final Marker... localParents) {
            //noinspection ForLoopReplaceableByForEach
            for (final Marker marker : localParents) {
                if (marker == parent) {
                    return true;
                }
            }
            return false;
        }
    

    With standard loop:

      private static boolean contains(org.apache.logging.log4j.Marker, org.apache.logging.log4j.Marker...);
        Code:
           0: iconst_0
           1: istore_2
           2: aload_1
           3: arraylength
           4: istore_3
           5: iload_2
           6: iload_3
           7: if_icmpge     29
          10: aload_1
          11: iload_2
          12: aaload
          13: astore        4
          15: aload         4
          17: aload_0
          18: if_acmpne     23
          21: iconst_1
          22: ireturn
          23: iinc          2, 1
          26: goto          5
          29: iconst_0
          30: ireturn
    

    With for-each:

      private static boolean contains(org.apache.logging.log4j.Marker, org.apache.logging.log4j.Marker...);
        Code:
           0: aload_1
           1: astore_2
           2: aload_2
           3: arraylength
           4: istore_3
           5: iconst_0
           6: istore        4
           8: iload         4
          10: iload_3
          11: if_icmpge     34
          14: aload_2
          15: iload         4
          17: aaload
          18: astore        5
          20: aload         5
          22: aload_0
          23: if_acmpne     28
          26: iconst_1
          27: ireturn
          28: iinc          4, 1
          31: goto          8
          34: iconst_0
          35: ireturn
    

    What is up with THAT Oracle?

    I've tried this with Java 7 and 8 on Windows 7.

    0 讨论(0)
提交回复
热议问题