Цикл foreach буквально переписан в цикл for с итератором?

В этом сообщении объясняется, что цикл foreach напрямую соответствует использованию итератора. Если я напишу цикл foreach, будет ли он буквально преобразован в for с итератором? В частности, данный цикл:

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

Могу ли я всегда звонить createList() только один раз, несмотря ни на что? Переписывается как:

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

на каком-то промежуточном этапе или просто получается тот же байт-код, что и выше?


person Bartek Maraszek    schedule 25.04.2014    source источник
comment
возможный дубликат Как работает Java для каждого цикла? - какая часть этого довольно подробного ответа или любой из здесь на SO, разве ты не понимаешь?   -  person Brian Roach    schedule 25.04.2014
comment
Я понимаю, что фрагменты кода эквивалентны. В некоторых ответах говорится, что он переводится. Я не понимаю, заменяет ли компилятор его вторым фрагментом или просто выводит тот же результат. Так или иначе, мне любопытно, гарантируется ли такое поведение самим языком или компилятором.   -  person Bartek Maraszek    schedule 25.04.2014
comment
@BrianRoach Предложенный вами дубликат неверен - он не решает проблему множественных оценок предмета цикла. Может быть хорошей идеей отозвать свой голос и надеяться, что другие VTC с моим дубликатом.   -  person Duncan Jones    schedule 25.04.2014
comment
@Duncan, сообщение, которое вы упомянули, и ссылка, предоставленная пользователем 1685993, объясняют мою основную озабоченность по поводу вызова функции. Мне до сих пор интересно, как перевод выглядит на практике (промежуточный этап или его отсутствие). Я думаю, что если бы не было промежуточного шага, было бы сложнее гарантировать, что конструкции всегда точно эквивалентны (правильно ли я думаю?). Может, кто-то просто случайно это знает :)   -  person Bartek Maraszek    schedule 25.04.2014
comment
Будет ли это реальная трансляция или просто эквивалентный вывод байт-кода, не имеет значения, поскольку компиляторы Java не обязаны когда-либо выводить свои промежуточные структуры данных. Пока вывод в байт-коде верен, компилятор Java (а существует больше компиляторов, чем тот, который предоставляется с JDK - например, компилятор Eclipse) может делать все, что захочет, чтобы получить результат.   -  person Erwin Bolwidt    schedule 25.04.2014


Ответы (2)


Согласно документации Oracle здесь действительно создается код, но он отличается в зависимости от типа используемого объекта.

Если вы используете массив, цикл foreach будет переведен как цикл for с индексом:

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

Если у вас есть объект Iterable, вы получите такой цикл с итератором:

for (I #i = Expression.iterator(); #i.hasNext(); ) {
    VariableModifiersopt TargetType Identifier = (TargetType) #i.next();
    Statement
}
person AHH    schedule 25.04.2014

AFAIK, он не проходит фазу перевода, он просто делает то же самое для Iterable

Одно отличие заключается в том, что вы не можете получить доступ к итератору для каждого, что означает, что вы не можете этого сделать.

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

но ты можешь сделать

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

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

Примечание: если у вас есть

public Integer[] createList();

тогда

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

такой же как

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

Примечание. Переменные $arr и $i созданы и недоступны для приложения. Возможно, вы сможете увидеть их в своем отладчике под другим именем.

person Peter Lawrey    schedule 25.04.2014