Java - разница между выражением окончания цикла - PullRequest
5 голосов
/ 26 февраля 2011

Мне просто любопытно: есть ли разница в скорости и производительности между реализацией этих двух циклов? Предположим, что метод size () возвращает длину массива, коллекции или объекта, который обрабатывает группу элементов (в действительности это XOM api).

Реализация 1:

int size = someArray.size();
for (int i = 0; i < size; i++) {
    // do stuff here
}

Реализация 2:

for (int i = 0; i < someArray.size(); i++) {
    // do stuff here
}

Ответы [ 6 ]

4 голосов
/ 26 февраля 2011

С точки зрения производительности, есть небольшая разница. Это связано с тем, что цикл можно оптимизировать так, чтобы поиск size () был встроен, что приводит к очень небольшому различию в производительности.

Основное отличие заключается в том, что размер изменяется во время цикла. В первом случае попытка будет повторяться фиксированное количество раз. Во втором случае количество итераций будет зависеть от окончательного размера ().

1 голос
/ 26 февраля 2011

Не беспокойтесь, оптимизация JVM в наши дни очень агрессивна.

Используйте 2-ую форму, чтобы она была более читабельной и, скорее всего, такой же быстрой. Преждевременная оптимизация Яда Яда.

А когда вам нужно улучшить скорость, всегда сначала делайте профиль, не догадайтесь.

Крайне маловероятно, что размер кэширования () в локальной переменной может заметно помочь вашему приложению. Если это так, вы должны выполнять простые операции над огромным набором данных. В этом случае вам вообще не следует использовать ArrayList.

1 голос
/ 26 февраля 2011

Да, есть разница.В первом цикле метод size () вызывается только один раз.Во втором он вызывается на каждой итерации.

Если итерация изменяет размер коллекции (что очень редко), требуется вторая.В большинстве случаев вы предпочитаете первый, но ограничивает область действия переменной размера:

for (int i = 0, size = someArray.size(); i < size; i++) {
    // ...
}

Но в большинстве случаев вам все равно следует предпочесть синтаксис foreach:

for (Foo foo : collection) {
    // ...
}

, который будет эффективно перебирать массив или коллекцию, даже для LinkedList, например, где индексированный доступ не оптимален.

1 голос
/ 26 февраля 2011

Первый фрагмент должен выполняться быстрее, так как он вызывает size() только один раз. Второй фрагмент вызывает size() N раз. В зависимости от вкл. это может привести к значительным штрафам, особенно если компилятору сложно встроить метод и / или метод size() не просто возвращает энергонезависимую переменную и т. д.

Я бы переписал это как for(int i=0, s=someCollection.size(); i<s; i++)

Примечание: у массивов нет метода size().

0 голосов
/ 06 апреля 2015

Всегда избегайте всего, что можно сделать вне цикла, например, вызовов методов, присвоения значений переменным или проверки условий.

Вызовы метода обходятся дороже, чем эквивалентный код без вызова, и повторяя вызовы метода снова и снова, вы просто добавляете накладные расходы в свое приложение.

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

Преимущества: -

Если компилятор не оптимизирует его, условие цикла будет рассчитываться для каждой итерации цикла.

Если значение условия не изменится, код будет выполняться быстрее, если вызов метода перемещен из цикла.

Примечание: -

Если метод возвращает значение, которое не изменится во время цикла, сохраните его значение во временной переменной перед циклом.

Следовательно, его значение сохраняется во временном переменном размере вне цикла, а затем используется в качестве условия завершения цикла.

0 голосов
/ 26 февраля 2011

Может быть стоит отметить, что эта конструкция:

for (String s : getStringsList()) {
    //...
}

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

...