6

I was trying to find the working of for-each loop when I make a function call. Please see following code,

public static int [] returnArr()
{
    int [] a=new int [] {1,2,3,4,5};
    return a;
}

public static void main(String[] args)
{
    //Version 1
    for(int a : returnArr())
    {
        System.out.println(a);
    }

    //Version 2
    int [] myArr=returnArr();
    for(int a : myArr)
    {
        System.out.println(a);
    }
}

In version 1, I'm calling returnArr() method in for-each loop and in version 2, I'm explicitly calling returnArr() method and assigning it to an array and then iterating through it. Result is same for both the scenarios. I would like to know which is more efficient and why.

I thought version 2 will be more efficient, as I'm not calling method in every iteration. But to my surprise, when I debugged the code using version 1, I saw the method call happened only once!

Can anyone please explain how does it actually work? Which is more efficient/better when I code for complex objects?

2
  • Well, you saw for yourself that there's no difference when you debugged the first version. Commented Feb 9, 2015 at 7:11
  • So, there is no difference in both the versions when it comes to efficiency of code? Commented Feb 9, 2015 at 7:37

4 Answers 4

4

The Java Language Specification shows the underlying compilation

Let L1 ... Lm be the (possibly empty) sequence of labels immediately preceding the enhanced for statement.

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

T[] #a = Expression;
L1: L2: ... Lm:
for (int #i = 0; #i < #a.length; #i++) {
    {VariableModifier} TargetType Identifier = #a[#i];
    Statement
}

where Expression is the right hand side of the : in an enhanced for statement (your returnArr()). In both cases, it gets evaluated only once: in version 1, as part of the enhanced for statement; in version 2, because its result is assigned to a variable which is then used in the enhanced for statement.

Sign up to request clarification or add additional context in comments.

Comments

1

I'm not going to copy paste from the Java Language Specification, like one of the previous answers did, but instead interpret the specification in a readable format.

Consider the following code:

for (T x : expr) {
    // do something with x
}

If expr evaluates to an array type like in your case, the language specification states that the resulting bytecode will be the same as:

T[] arr = expr;
for (int i = 0; i < arr.length; i++) {
    T x = arr[i];
    // do something with x
}

The difference only is that the variables arr and i will not be visible to your code - or the debugger, unfortunately. That's why for development, the second version might be more useful: You have the return value stored in a variable accessible by the debugger.

In your first version expr is simply the function call, while in the second version you declare another variable and assign the result of the function call to that, then use that variable as expr. I'd expect them to exhibit no measurable difference in performance, as that additional variable assignment in the second version should be optimized away by the JIT compiler, unless you also use it elsewhere.

Comments

1

The compiler is calling the method returnArr() only once. compile time optimization :)

Byte code :

 public static void main(java.lang.String[]);
   descriptor: ([Ljava/lang/String;)V
   flags: ACC_PUBLIC, ACC_STATIC
   Code:
     stack=2, locals=6, args_size=1

** case -1  start ***
        0: invokestatic  #20                 // Method returnArr:()[I  --> called only once. 
        3: dup
        4: astore        4
        6: arraylength
        7: istore_3
        8: iconst_0
        9: istore_2
       10: goto          28
       13: aload         4    --> loop start
       15: iload_2
       16: iaload
       17: istore_1
       18: getstatic     #22                 // Field java/lang/System.out:Ljav
/io/PrintStream;
       21: iload_1
       22: invokevirtual #28                 // Method java/io/PrintStream.prin
ln:(I)V
       25: iinc          2, 1
       28: iload_2
       29: iload_3
       30: if_icmplt     13


***case -2  start****

       33: invokestatic  #20                 // Method returnArr:()[I
       36: astore_1
       37: aload_1
       38: dup
       39: astore        5
       41: arraylength
       42: istore        4
       44: iconst_0
       45: istore_3
       46: goto          64
       49: aload         5   --> loop start case 2
       51: iload_3
       52: iaload
       53: istore_2
       54: getstatic     #22                 // Field java/lang/System.out:Ljav
/io/PrintStream;
       57: iload_2
       58: invokevirtual #28                 // Method java/io/PrintStream.prin
ln:(I)V
       61: iinc          3, 1
       64: iload_3
       65: iload         4
       67: if_icmplt     49
       70: return

Note : I am using jdk 8.

2 Comments

Yup, I observed the one-time call while debugging it. :) Still I want to know which version is better when you code?
@Abhishek - Either the compiler or the JIT will optimize your code. If you ask from a logical perspective, then version 2 is good.
1

foreach internally uses list iterator to traverse through list and yes there is a difference between them.

If you just want to traverse the list and do not have any intension to modify it then you should use foreach else use list iterator.

for (String i : myList) {
    System.out.println(i);
    list.remove(i); // Exception here
} 

Iterator it=list.iterator();
while (it.hasNext()){
    System.out.println(it.next());
    it.remove(); // No Exception
}

Also if using foreach you are passing a list which is null then you will get null pointer exception in java.util.ArrayList.iterator()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.