Which is more efficient, a for-each loop, or an iterator?

后端 未结 7 1526
别那么骄傲
别那么骄傲 2020-11-22 16:00

Which is the most efficient way to traverse a collection?

List  a = new ArrayList();
for (Integer integer : a) {
  integer.toSt         


        
7条回答
  •  半阙折子戏
    2020-11-22 16:33

    foreach uses iterators under the hood anyway. It really is just syntactic sugar.

    Consider the following program:

    import java.util.List;
    import java.util.ArrayList;
    
    public class Whatever {
        private final List list = new ArrayList<>();
        public void main() {
            for(Integer i : list) {
            }
        }
    }
    

    Let's compile it with javac Whatever.java,
    And read the disassembled bytecode of main(), using javap -c Whatever:

    public void main();
      Code:
         0: aload_0
         1: getfield      #4                  // Field list:Ljava/util/List;
         4: invokeinterface #5,  1            // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
         9: astore_1
        10: aload_1
        11: invokeinterface #6,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
        16: ifeq          32
        19: aload_1
        20: invokeinterface #7,  1            // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
        25: checkcast     #8                  // class java/lang/Integer
        28: astore_2
        29: goto          10
        32: return
    

    We can see that foreach compiles down to a program which:

    • Creates iterator using List.iterator()
    • If Iterator.hasNext(): invokes Iterator.next() and continues loop

    As for "why doesn't this useless loop get optimized out of the compiled code? we can see that it doesn't do anything with the list item": well, it's possible for you to code your iterable such that .iterator() has side-effects, or so that .hasNext() has side-effects or meaningful consequences.

    You could easily imagine that an iterable representing a scrollable query from a database might do something dramatic on .hasNext() (like contacting the database, or closing a cursor because you've reached the end of the result set).

    So, even though we can prove that nothing happens in the loop body… it is more expensive (intractable?) to prove that nothing meaningful/consequential happens when we iterate. The compiler has to leave this empty loop body in the program.

    The best we could hope for would be a compiler warning. It's interesting that javac -Xlint:all Whatever.java does not warn us about this empty loop body. IntelliJ IDEA does though. Admittedly I have configured IntelliJ to use Eclipse Compiler, but that may not be the reason why.

提交回复
热议问题