Повторять цикл for или цикл while?
Я часто вижу такой код:
Iterator i = list.iterator();
while(i.hasNext()) {
...
}
но я пишу это (когда Java 1.5 недоступна или не может использоваться для каждого) как:
for(Iterator i = list.iterator(); i.hasNext(); ) {
...
}
так как
- Короче
- Это держит
i
в меньшем объеме - Это уменьшает вероятность путаницы. (Является
i
используется вне времени? Гдеi
объявлена?)
Я думаю, что код должен быть настолько простым для понимания, насколько это возможно, так что мне нужно только создавать сложный код, чтобы делать сложные вещи. Как вы думаете? Что лучше?
15 ответов
Я предпочитаю цикл for, поскольку он также устанавливает область действия итератора только для цикла for.
Существуют подходящие варианты использования конструкций while, for и foreach:
while
- Используйте это, если вы выполняете итерацию, и решающий фактор для цикла или нет основан только на условии. В этой конструкции цикла поддержание индекса является лишь второстепенной задачей; все должно быть основано на условииfor
- Используйте это, если вы зацикливаетесь, и вашей главной заботой является индекс массива / коллекции / списка. Более полезно использовать for, если вы, вероятнее всего, пройдете все элементы в любом случае и в определенном порядке (например, пройдете назад по отсортированному списку, например).foreach
- Используйте это, если вам просто нужно просмотреть вашу коллекцию независимо от порядка.
Очевидно, есть исключения из вышеперечисленного, но это общее правило, которое я использую, когда решаю использовать какой. Это, как говорится, я склонен использовать foreach
чаще.
Почему бы не использовать конструкцию for-each? (Я давно не использовал Java, но он существует в C#, и я уверен, что в Java 1.5 тоже есть):
List<String> names = new ArrayList<String>();
names.add("a");
names.add("b");
names.add("c");
for (String name : names)
System.out.println(name.charAt(0));
Я думаю, что сфера является самой большой проблемой здесь, как вы указали.
В примере "while" итератор объявлен вне цикла, поэтому он будет продолжать существовать после завершения цикла. Это может вызвать проблемы, если этот же итератор будет использован снова в какой-то более поздний момент. Например Вы можете забыть инициализировать его перед использованием в другом цикле.
В примере "for" итератор объявлен внутри цикла, поэтому его область действия ограничена циклом. Если вы попытаетесь использовать его после цикла, вы получите ошибку компилятора.
ИМХО, цикл for менее читабелен в этом сценарии, если вы посмотрите на этот код с точки зрения английского языка. Я работаю над кодом, где автор ругает за цикл, и это не красиво. Сравните следующее:
for (; (currUserObjectIndex < _domainObjectReferences.Length) && (_domainObjectReferences[currUserObjectIndex].VisualIndex == index); ++currUserObjectIndex)
++currNumUserObjects;
против
while (currUserObjectIndex < _domainObjectReferences.Length && _domainObjectReferences[currUserObjectIndex].VisualIndex == index)
{
++currNumUserObjects;
++currUserObjectIndex;
}
Если вы собираетесь использовать итератор только один раз и выбросить его, предпочтительнее использовать вторую форму; в противном случае вы должны использовать первую форму
Я согласен, что цикл for более понятен и более уместен при итерации.
Цикл while подходит для опроса, или когда число циклов, удовлетворяющих условию выхода, будет меняться в зависимости от активности внутри цикла.
Не то чтобы это, вероятно, имеет значение в этом случае, но компиляторы, виртуальные машины и процессоры обычно имеют специальные методы оптимизации, которые они используют под капотом, которые улучшат производительность циклов (и в ближайшем будущем параллельно), в общем, они не делают этого с цикл while (потому что его сложнее определить, как он будет работать на самом деле). Но в большинстве случаев ясность кода должна превосходить оптимизацию.
Используя цикл for, вы можете работать с одной переменной, поскольку она устанавливает область видимости переменной только для текущего цикла. Однако это невозможно в цикле while. Например:
Int I; для (i=0; in1;i++) сделать что-то..
ибо (i=0;i n2;i+=2) сделайте что-нибудь.
Так что после 1-го цикла я = n1-1 в конце. Но при использовании второго цикла вы можете снова установить i в 0. Однако
int i=0;
в то время как (я меньше, чем предел) {сделать что-то..; я ++; }
Следовательно, я установлен на предел-1 в конце. Так что вы не можете использовать то же самое я в другом цикле while.
Я был для цикла для ясности. Хотя я использую цикл while, когда сталкиваюсь с каким-то недетерминированным условием.
Я согласен, что цикл for следует использовать всякий раз, когда это возможно, но иногда в теле цикла используется более сложная логика, управляющая итератором. В этом случае вы должны идти с какое-то время.
Хотя оба они действительно хороши, я склонен использовать первый пример, потому что его легче читать.
В каждой строке с циклом while() происходит меньше операций, что облегчает понимание кем-то новичка в коде, что происходит.
Этот тип конструкции также позволяет мне группировать инициализации в общем месте (в верхней части метода), что также упрощает комментирование для меня и концептуализацию для того, кто читает его впервые.
И то, и другое хорошо, но помните, что иногда полезен прямой доступ к Итератору (например, если вы удаляете элементы, соответствующие определенному условию - вы получите исключение ConcurrentModificationException, если вы выполните collection.remove(o) внутри for(T o: коллекция) петля).
Я предпочитаю писать синтаксис for(blah: blah) [foreach] почти все время, потому что он кажется мне более понятным. Концепция итераторов вообще не имеет параллелей вне программирования
Академия, как правило, предпочитает цикл "время", поскольку это упрощает рассуждения о программах. Я обычно предпочитаю структуры цикла for или foreach, поскольку они упрощают чтение кода.
Либо в порядке. Я использую для () себя, и я не знаю, есть ли проблемы компиляции. Я подозреваю, что они оба оптимизированы почти до одного и того же.