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()
,
Всегда избегайте всего, что можно сделать вне цикла, например, вызовов методов, присвоения значений переменным или проверки условий.
Вызовы методов обходятся дороже, чем эквивалентный код без вызова, и повторяя вызовы методов снова и снова, вы просто добавляете накладные расходы в свое приложение.
Переместите любые вызовы методов из цикла, даже если это требует переписывания кода.
Выгоды:-
Если компилятор не оптимизирует его, условие цикла будет вычисляться для каждой итерации цикла.
Если значение условия не изменится, код будет выполняться быстрее, если вызов метода перемещен из цикла.
Заметка:-
Если метод возвращает значение, которое не изменится во время цикла, сохраните его значение во временной переменной перед циклом.
Следовательно, его значение сохраняется во временной переменной размера вне цикла, а затем используется в качестве условия завершения цикла.