Вызывает ли for-each в Java встроенный метод (который возвращает коллекцию) для каждой итерации?

Если есть вызов метода MyClass.returnArray(), и я перебираю массив, используя конструкцию for-each (также называемую «расширенным циклом for»):

for (ArrayElement e : MyClass.returnArray()) {
   //do something
}

будет ли тогда метод returnArray() вызываться для каждой итерации?


person d56    schedule 21.07.2010    source источник


Ответы (4)


Нет, не будет. Результат первого вызова будет сохранен в скомпилированном коде во временной переменной.

Из Effective Java 2nd. Ред., пункт 46:

Обратите внимание, что использование цикла for-each не влияет на производительность даже для массивов. Фактически, в некоторых случаях он может давать небольшое преимущество в производительности по сравнению с обычным циклом for, поскольку он вычисляет предел индекса массива только один раз.

person Péter Török    schedule 21.07.2010
comment
Если вас интересует отрицательное голосование, я согласен с выводом, но я не думаю, что процитированная вами часть действительно хорошо объясняет, почему. В основном речь идет об индексе массива, который не является предметом обсуждения и не может объяснить, не говоря уже о том, чтобы доказать, что метод returnArray в выражении вызывается только один раз. - person Maarten Bodewes; 02.01.2020

Из спецификации языка Java:

EnhancedForStatement:
    for ( VariableModifiersopt Type Identifier: Expression) Statement

и позже:

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

Это (в псевдокоде) эквивалент расширенного цикла for для массивов. И становится ясно, что Expression оценивается один раз, и результирующий массив присваивается T[] a.

Поэтому совершенно безопасно использовать даже сложные выражения в расширенном операторе цикла for.

person Andreas Dolk    schedule 21.07.2010

No.

Цикл for — это просто синтаксический сахар. Он ведет себя по-другому в зависимости от того, применяется ли он к аргументу Array или к объекту, реализующему интерфейс Iterable.

Для объектов Iterable цикл расширяется примерно так:

Iterator<ArrayElement> iter = iterableObject.iterator();
while (iter.hasNext()) {
   ArrayElement e = iter.next();
   // do smth
}

То, что на самом деле делает ваш примерный код, выглядит примерно так:

Object[] temp = Method.returnArray();
for ( int i = 0; i < temp.length; i++ ) {
  ArrayElement e = (ArrayElement) temp[i];
  // do smth
}     
person Lucas    schedule 21.07.2010
comment
Это совершенно верно для всех подклассов Iterable, но расширенный цикл for можно использовать и с массивами, и я думаю, в этом и был смысл вопроса. Это все еще «синтаксический сахар», но немного другой. - person Andreas Dolk; 21.07.2010

Нет, он будет вызван один раз. Это не похоже на условие завершения стандартного цикла for, которое оценивается на каждой итерации.

person Eyal Schneider    schedule 21.07.2010