0

I've using the "foreach" loop in my Java applications for a long time. Recently I started wondering if there is any significative difference in performance (or even in the result) between:

Collection<String> collection = someMethod();
for(String element : collection) { ... }

and:

for(String element : someMethod()) { ... }

What if instead of a Collection it is a List, a Map, a Set or an array?

jeojavi
  • 876
  • 1
  • 6
  • 15
  • 1
    Why would you suspect a performance difference? – Philipp May 06 '14 at 12:13
  • How did you find the difference in performance? – Braj May 06 '14 at 12:14
  • possible duplicate of [Is there a performance difference between a for loop and a for-each loop?](http://stackoverflow.com/questions/256859/is-there-a-performance-difference-between-a-for-loop-and-a-for-each-loop) – Peter Lawrey May 06 '14 at 12:15
  • @Philipp I've read the first option is the "best practice" and I wanted to know if there is any performance reason for that – jeojavi May 06 '14 at 12:15
  • @JaviFernández there is no performance difference. It's more about not having to know the returned collection type, if anything. – Rogue May 06 '14 at 12:15
  • 1
    I'd prefer the former. If you are wondering if someMethod() is called multiple times (it shouldn't be), put a debug statement in there. – Engineer2021 May 06 '14 at 12:17
  • @PeterLawrey not the same question – jeojavi May 06 '14 at 12:20
  • Thank you very much. So it's more about style than performance, isn't it? – jeojavi May 06 '14 at 12:22
  • @JaviFernández Basically the same answer. The code and result is much the same between the two alternatives. – Peter Lawrey May 06 '14 at 12:54
  • 1
    I think he was being afraid that someMethod() will be called multiple times(more exactly: for each iteration) , resulting into a tiny-to-huge performance difference, depending on what `someMethod()` is doing. I think it is a duplicate of : http://stackoverflow.com/questions/3298202/does-advanced-for-each-loop-in-java-call-method-that-returns-an-array-to-iterate – Daniel May 06 '14 at 13:27

4 Answers4

3

The difference between both codes can be seen in their generated bytecodes.

The first one has extra two instructions over the second one; it stores the return value of someMethod() on the local stack and then loads it again for accessing it's iterator.

However the second one immediately uses the Iterator without storing the return value of someMethod() on the local stack.

Below code shows the elimination of 3: and 4: instructions.

First:

Collection<String> collection = someMethod();
for(String element : collection) { ... }

     0: invokestatic  #3                  // Call someMethod()
     3: astore_1                          // Store the result as first item on local stack
     4: aload_1                           // Load the Collection again into operand stack
     5: invokeinterface #4,  1            // Get Iterator (of Collection) - InterfaceMethod java/util/Collection.iterator:()Ljava/util/Iterator;
    10: astore_2                          // Store Iterator on local stack #2
    11: aload_2                           // LOOP STARTS - Load iterator
    12: invokeinterface #5,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
    17: ifeq          33
    20: aload_2       
    21: invokeinterface #6,  1            // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
    26: checkcast     #7                  // class java/lang/String
    29: astore_3      
    30: goto          11                  // LOOP ENDS
    33: return

Second

for(String element : someMethod()) { ... }

     0: invokestatic  #3                  // Call someMethod() 
     3: invokeinterface #4,  1            // Get Iterator (of Collection) - Interface Method java/util/Collection.iterator:()Ljava/util/Iterator;/
     8: astore_1                          // Store Iterator on local stack #2  
     9: aload_1                           // LOOP STARTS - Load iterator
    10: invokeinterface #5,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
    15: ifeq          31
    18: aload_1       
    19: invokeinterface #6,  1            // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
    24: checkcast     #7                  // class java/lang/String
    27: astore_2      
    28: goto          9                   // LOOP ENDS
    31: return       

BTW, I don't think that they will have a big difference in terms of performance since both have 9 instructions inside the loop.

Onur Aktaş
  • 410
  • 4
  • 8
2

There is no visible performance difference between the two. The first way is more elegant and readable than the second one. But from performance point of view its not a deterrent. Both produce identical bytecode for the 'inside the loop' part.

Nazgul
  • 1,892
  • 1
  • 11
  • 15
1

It's a semantic difference, you won't see any real performance change in your code as a result of assigning a method return value to a local variable. Lists, Sets, Map entry sets, arrays are all iterable in the for-each loop, so they are all fine and result in you not having to know the return collection type.

Rogue
  • 11,105
  • 5
  • 45
  • 71
1

For compatibility you shall use the second and if you know the result is never null.

The first shall not be used if you dont need the collection anymore.

I prefer a third suggestion:

Collection<String> collection = someMethod();
if (collection != null) {
    for(String element : collection) { ... }
}

Regards.

Grim
  • 1,938
  • 10
  • 56
  • 123
  • 1
    I usually prefer to return an empty collection if `someMethod()` is written by me and not part of some 3rd party library, just to avoid these annoying checkings against null. – Daniel May 06 '14 at 13:23
  • I really like you to be my collegue. Can i ask you something? how do you think about `assert collection != null;`? – Grim May 06 '14 at 13:35
  • 1
    I think it is a really bad idea to use assertion in these situations(before iterating over a collection) because I would not like my program to terminate if the collection is null. IMHO assertions have their place in testing , not in production code, but again: this is only my humble opinion . – Daniel May 06 '14 at 13:57