Java - Разница между выражением окончания цикла

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

Реализация 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 ответов

Решение

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Выгоды:-

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

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

Заметка:-

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

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

Другие вопросы по тегам