7

This post explains that foreach loop directly corresponds to using iterator. If I write a foreach loop is it literally going to be transformed into for with iterator? In particular, given loop:

for(Integer i : createList()){
    System.out.println(i);
}

Am I guaranteed to always call createList() only once no matter what? Is it rewritten as:

for(Iterator<Integer> i = createList().iterator(); i.hasNext(); ) {
    System.out.println(i.next());
}

in some kind of intermediate step or just happens to produce the same bytecode as the above?

Community
  • 1
  • 1
Bartek Maraszek
  • 1,404
  • 2
  • 14
  • 31
  • I understand that the code snippets are equivalent. Some of the answers given say that "it gets translated". I don't understand if the compiler literally swaps it with the second snippet or just produces the same output. This way or another I'm curious if this behavior is guaranteed by the language itself or by the compiler. – Bartek Maraszek Apr 25 '14 at 11:43
  • 2
    @BrianRoach Your proposed duplicate is not correct - it doesn't address the issue of multiple evaluations of the loop subject. Might be a good idea to retract your vote and hope others VTC with my duplicate. – Duncan Jones Apr 25 '14 at 11:52
  • @Duncan, the post you mentioned and the link provided by user1685993, explain my main concern about the function call. I still wonder how the translation looks like in practice (an intermediate step or lack thereof). I think if there was no intermediate step, it might be harder to guarantee that the constructions are always exactly equivalent (am I thinking right?). Maybe someone just happens to know this :) – Bartek Maraszek Apr 25 '14 at 12:22
  • Whether there is a "real" translation or just the equivalent bytecode output is irrelevant, since Java compilers are not required to ever output their intermediate data structures. As long as the output in bytecode is correct, a Java compiler (and there are more compilers than just the one provided with the JDK - like the Eclipse compiler) can do whatever it wants to arrive at the output. – Erwin Bolwidt Apr 25 '14 at 16:05

2 Answers2

6

According to Oracle documentation on this, there is indeed code being generated, but it differs according to the type of the used obejct.

If you are using an array, the foreach loop will be translated as a for loop with index:

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

If you have an Iterable object, you get a loop with iterator like this:

for (I #i = Expression.iterator(); #i.hasNext(); ) {
    VariableModifiersopt TargetType Identifier = (TargetType) #i.next();
    Statement
}
AHH
  • 981
  • 2
  • 10
  • 26
1

AFAIK, It doesn't go through a translation phase, it just does the same thing for Iterable

One difference is you cannot access the Iterator in a for-each meaning you can't do this

for(Integer i: createList()) {
   if (i == 5) iter.remove(); // or whatever the iterator is called.
}

but you can do

for(Iterator<Integer> iter = createList().iterator(); iter.hasNext(); ) {
    Integer i = iter.next();

    if (i == 5) iter.remove();
}

Note: if you have

public Integer[] createList();

then

for(Integer i : createList()){
    System.out.println(i);
}

is the same as

{
    Integer[] $arr = createList();
    for(int $i = 0; $i < $arr.length; $i++) {
        Integer i = $arr[$i];
        System.out.println(i);
    }
}

Note: The variables $arr and $i are made up and are not available to the application. You might be able to see them in your debugger, with a different name.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130