Вопрос по java – Лучшая практика в цикле `For` в Java [дубликаты]

3

Possible Duplicate:
for loop optimization

В Java у меня есть блок кода:

List e = {element1, element2, ...., elementn};
for(int i = 0; i < e.size(); i++){//Do something in here
};

и еще один блок:

List e = {element1, element2, ...., elementn};
int listSize = e.size();
for(int i = 0; i < listSize; i++){//Do something in here
};

Я думаю, что второй блок лучше, потому что в первом блоке, еслиi++мы должны рассчитатьe.size() еще раз, чтобы сравнить состояние вfor петля. Это правильно или неправильно? И сравнивая два блока выше, для чего лучше всего писать? И почему? Объясните и попробуйте этот цикл самостоятельно

Второй, потому что вы не рассчитываете размер списка на каждой итерации. Nuno Costa

Ваш Ответ

12   ответов
3

Я бы всегда использовал (если вам нужна индексная переменная):

List e = {element1, element2, ...., elementn};
for(int i = 0, size = e.size(); i < size; i++){
    // Do something in here
};

посколькуe.size() может быть дорогой операцией.

Ваш второй вариант не годится, так как он вводит новую переменную внеfor петля. Я рекомендую держать переменную видимость как можно более ограниченной.

В противном случае

for (MyClass myObj : list) {
    // Do something here
}

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

+1 для инициализации переменной размера в цикле for, я думаю, что это довольно элегантно (хотя я не верю в микрооптимизацию, если только она НЕ ДЕЙСТВИТЕЛЬНО необходима). Во всяком случае, хороший фрагмент :)
-1 e.size () это НЕ дорогая операция, с чего бы это !? если вы декомпилируете реализацию метода e.size (), вы увидите, что она просто возвращает переменную размера, а это не «дорого». операция.
1

Да, вторая форма немного более эффективна, так как вы не повторяетеsize() вызов метода. Компиляторы хорошо делают такую оптимизацию сами.

However, it's unlikely that this would be the performance bottleneck of your application. Избегайте преждевременной оптимизации, Сделайте ваш код чистым и читаемым в первую очередь.

14

Лично я бы вместо этого использовал расширенный оператор for:

for (Object element : e) {
    // Use element
}

Если только ты неneed Индекс, конечно.

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

+1 за встроенное слово .......
@Kingfisher: этоspecifically для Android, где JIT был более примитивным, хотя я не удивлюсь, узнав, что теперь он все равно справляется с этой ситуацией. А вообще,don't micro-optimize without evidence.
http://developer.android.com/guide/practices/design/performance.html Как я уже читал в ссылке, второй блок лучше первого! :( Kingfisher Phuoc
6

Обычно самый короткий и читаемый код - лучший выбор, при прочих равных условиях. В случае Java, расширенный цикл for (который работает с любым классом, который реализуетIterable) это путь.

for (Object object : someCollection) { // do something }

Что касается только тех двух, которые вы опубликовали, я думаю, что первый - лучший вариант. Это более читабельно, и вы должны помнить, что JIT попытается оптимизировать большую часть кода, который вы пишете, в любом случае.

EDIT: Вы слышали фразу «преждевременная оптимизация - корень всего зла»? Ваш второй блок - пример преждевременной оптимизации.

@Kingfisher, это интересно. Но в начале документа говорится: «Этот документ посвящен микрооптимизации для Android, поэтому предполагается, что вы уже использовали профилирование, чтобы точно определить, какой код должен быть оптимизирован».
+1 достижимый и всеобъемлющий
Link Here  Как я прочитал в ссылке здесь, второй блок лучше, чем первый! Kingfisher Phuoc
Как предполагает Джон Скит, если по какой-то причине вам нужен индекс в коллекцию, которую вы перебираете, используйте первую форму цикла.
0

Я не уверен, но я думаю, что оптимизатор Java заменит значение статическим значением, так что в конце оно будет таким же.

1

HotSpot переместит e.size () из цикла в большинстве случаев. Таким образом, он будет рассчитывать размер списка только один раз.

Что касается меня, я предпочитаю следующие обозначения:

for (Object elem: e) {
   //Do something
}
-1

вторая лучше, потому что в первом цикле в теле, может быть, вы сделаете это утверждение e.remove, и тогда размер e будет изменен, поэтому лучше сохранить размер в параметре перед циклом

нет, он не будет выдавать никаких исключений, если вы удалите элемент списка внутри лога, просто вы получите элемент без сканирования
нет, не будет, потому что размер списка в первую очередь вычисляется динамически для каждого значения i, он не является статическим
Если вы удалите элемент из списка, размер действительно изменится, поэтому граница вашего цикла будет нарушена. Для меня это звучит как аргумент в пользу первой формы (хотя вы & d;also должен уменьшитьi чтобы не пропустить элемент).
Я предполагаю, что на самом деле он просто выдаст исключение IndexOutOfBoundsException, если вы не настроите переменную, используемую для отслеживания размера списка.
Разве это не вызывает исключение ConcurrentModificationException (или что-то в этом роде)?
0

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

Спасибо @JonSkeet. Но во многих местах это часто неправильно или неправильно понимают. Я также подумал, что лучшие практики означают написание кода, который будет слишком легок для выполнения JVM.
Лучшая практика предлагает писать наиболееreadable сначала код, а не микрооптимизация ...
4

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

+1 Хорошее отношение
0

Я думаю, что сейчас у нас есть тенденция писать короткий и понятный код, поэтому первый вариант лучше.

0

Чтобы избежать всей этой нумерации, а также итераторов и проверок при написании кода, используйте следующий простой наиболее читаемый код, который имеет максимальную производительность. Почему это имеет максимальную производительность (подробности уточняются)

for (Object object : aCollection) { 
// Do something here
}

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

1

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

List e = {element1, element2, ...., elementn};
int listSize = e.size();
int i=0;
for(i = 0; i < listSize; i++){//Do something in here
};

Похожие вопросы