Разница между перемещением итератора вперед с помощью оператора for и оператора while - PullRequest
14 голосов
/ 05 февраля 2009

Когда я использую Итератор Объекта, я использую цикл while (как написано в каждой книге, изучающей Java, как Мышление в Java Брюса Экеля):

Iterator it=...

while(it.hasNext()){
    //...
}

но иногда я видел, что вместо этого кто-то использует для цикла :

Iterator it=...
for (Iterator it=...; it.hasNext();){
    //...
}

Я не понимаю этот выбор:

  • Я использую для цикла , когда у меня есть коллекция с порядковой последовательностью (в виде массива) или со специальным правилом для шага (обычно объявленного как простое приращение counter++).
  • Я использую цикл while , когда цикл завершается с помощью «У меня нет ограничений», а только логическое условие для выхода.

Это вопрос стилевого кодирования без какой-либо другой причины или существует какая-то другая логика (например, производительность), которую я не знаю?

Спасибо за каждый отзыв

Ответы [ 5 ]

32 голосов
/ 05 февраля 2009

Правильный синтаксис для цикла for:

for (Iterator it = ...; it.hasNext(); ){
    //...
}

(Предыдущее объявление в вашем коде является излишним, равно как и лишняя точка с запятой в заголовке цикла for.)

Независимо от того, используете ли вы этот синтаксис или цикл while, дело вкуса, и то и другое в точности соответствует. Общий синтаксис цикла for:

for (<init stmt>; <loop cond>; <iterate stmt>) { <body>; }

, что эквивалентно:

<init stmt>;
while (<loop cond>) { <body>; <iterate stmt>; }

Редактировать: На самом деле, две вышеуказанные формы не полностью эквивалентны, , если (как в вопросе), переменная объявляется с помощью оператора init. В этом случае будет разница в области действия переменной итератора. При использовании цикла for область действия ограничена самим циклом, в случае цикла while, однако область действия распространяется до конца включающего блока (что не вызывает большого удивления, поскольку объявление находится вне цикла).

Кроме того, как отмечали другие, в более новых версиях Java существует сокращенная запись цикла for:

for (Iterator<Foo> it = myIterable.iterator(); it.hasNext(); ) {
    Foo foo = it.next();
    //...
}

можно записать как:

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

С помощью этой формы вы, конечно, потеряете прямую ссылку на итератор, что необходимо, например, если вы хотите удалить элементы из коллекции во время итерации.

9 голосов
/ 05 февраля 2009

Целью объявления Iterator в цикле for является минимизация области видимости ваших переменных , что является хорошей практикой.

Когда вы объявляете Iterator вне цикла, ссылка остается действительной / активной после завершения цикла. В 99,99% случаев вам не нужно продолжать использовать Iterator после завершения цикла, поэтому такой стиль может привести к таким ошибкам:

//iterate over first collection
Iterator it1 = collection1.iterator();
while(it1.hasNext()) {
   //blah blah
}

//iterate over second collection
Iterator it2 = collection2.iterator();
while(it1.hasNext()) {
   //oops copy and paste error! it1 has no more elements at this point
}
9 голосов
/ 05 февраля 2009

Это просто стиль, и, как и вы, я предпочитаю цикл for при использовании чего-либо с индексом. Если вы используете Java 5, вы все равно должны использовать цикл foreach для всей коллекции:

Collection<String> someCollection = someCollectionOfString();
for (String element : someCollection) {
....
}
4 голосов
/ 05 февраля 2009

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

На самом деле, есть и третий способ. Например, вместо письма

for (Iterator<SomeObject> it = foo.iterator(); it.hasNext();) {
  SomeObject so = foo.next();
}

чаще всего можно написать

for (SomeObject so: foo) {...}

Эти два равны одному и тому же ...

2 голосов
/ 05 февраля 2009

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

Одно конкретное конкретное преимущество конструкции long for loop заключается в том, что у вас есть ссылка на итератор, и поэтому вы можете вызывать для него методы, отличные от next(). В частности, hasNext() часто может быть полезно для вызова - представьте, если вы хотите распечатать список строк через запятую:

StringBuilder sb = new StringBuilder();
for (Iterator it=...; it.hasNext();){
   sb.append(it.next());
   if (it.hasNext())
      sb.append(", ");
}

Различать случай «это последний» можно только в том случае, если вы используете более подробный цикл for.

...