8

I am likely trying to be over-efficient, but I have been wondering which of the following two code samples would execute more quickly.

Assume that you have a reference to an object which contains an ArrayList of Strings and you want to iterate through that list. Which of the following is more efficient (even if only marginally so)?

for(String s : foo.getStringList())
    System.out.println(s);

Or

ArrayList<String> stringArray = foo.getStringList();
for(String s : stringArray)
    System.out.println(s);

As you can see, the second loop initializes a reference to the list instead of calling for it every iteration, as it seems the first sample does. Unless this notion is completely incorrect and they both function the same way because the inner workings of Java create their own reference variable.

So my question is, which is it?

StrongJoshua
  • 975
  • 10
  • 24
  • I'm having to think back to CS courses. I think they would be equivalent. You should be able to observe this by running the program in a debugger. There should be some sort of reference in the variable list to the object returned from `foo.getStringList()` – Freiheit Apr 23 '15 at 02:29
  • I always go with first option there just because the scope of stringArray on second code is wide. I prefer to keep the scope as narrow as possible. – Jimmy Apr 23 '15 at 02:29
  • @Jimmy but does the scope matter if you won't be using the same variable name again and the other class will continue to hold onto the list anwyays? – StrongJoshua Apr 23 '15 at 02:33
  • since it would be temporary hold on the reference even in first loop, the one to be popped out first from the method stack would be the reference hold on code sample one, than the sample 2. Other than that, it really does not matter. – Jimmy Apr 23 '15 at 03:00

3 Answers3

9

There's no difference, because both loops only end up getting and maintaining a reference to an Iterator for the expression at the start of the loop. Here's an excerpt from the Java Language Specification:

The enhanced for statement is equivalent to a basic for statement of the form:

for (I #i = Expression.iterator(); #i.hasNext(); ) {
    VariableModifiersopt TargetType Identifier =
        (TargetType) #i.next();
    Statement
}
that other guy
  • 116,971
  • 11
  • 170
  • 194
3

I am likely trying to be over-efficient

Definitely so. Don't try now1, write a readable code and it'll be fine. Fine and also fast as standard code is what gets most attention from the compiler guys. You really need to know a lot about Java before you can make a good guess about what's efficient (and you can be never sure).

As you can see, the second loop initializes a reference to the list instead of calling for it every iteration

And so does the first loop. Why? Imagine it wouldn't. Imagine foo.getStringList() would return something else every time it gets called. How could you iterate? Note that using indexes doesn't count, as not every Iterable is a List.

The for-each loop is a shortcut for using an Iterator. An Iterator gets obtained just once, and then hasNext and next gets called on it. Obviously, there's no place to evaluate the Iterable multiple times.


1 Using a good algorithms and/or data structure is a different story. Things like bubble sort are to be avoided.

maaartinus
  • 44,714
  • 32
  • 161
  • 320
3

Yes. The shorthand form does not re-fetch the iterator on each iteration of the loop, if you examine the bytecode of a method like (with javap -v)

public static void main(String[] args) {
    List<String> al = Arrays.asList("a", "b");
    for (String str : al) {
        System.out.println(str);
    }
}

you would see that invokeinterface #28, 1 is only called once

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=4, locals=4, args_size=1
         0: iconst_2
         1: anewarray     #16                 // class java/lang/String
         4: dup
         5: iconst_0
         6: ldc           #18                 // String a
         8: aastore
         9: dup
        10: iconst_1
        11: ldc           #20                 // String b
        13: aastore
        14: invokestatic  #22                 // Method java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List;
        17: astore_1
        18: aload_1
        19: invokeinterface #28,  1           // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
        24: astore_3
        25: goto          45
        28: aload_3
        29: invokeinterface #34,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
        34: checkcast     #16                 // class java/lang/String
        37: astore_2
        38: getstatic     #40                 // Field java/lang/System.out:Ljava/io/PrintStream;
        41: aload_2
        42: invokevirtual #46                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        45: aload_3
        46: invokeinterface #52,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
        51: ifne          28
        54: return
Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249