2009-02-05 4 views
15

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

Iterator it=... 

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

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

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

Я не»понять этот выбор:

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

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

Спасибо за любой отзыв

+0

Существует пример преобразования 'Iterator' в совместимый с каждым циклом 'Iterable' в http://stackoverflow.com/questions/2598219/java-why-cant-iterate-over-an-iterator/ – Vadzim

ответ

32

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

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

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

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

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

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

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

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

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

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

можно записать в виде:

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

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

+0

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

+0

@ Майкл: Там вы идете. –

9

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

Collection<String> someCollection = someCollectionOfString(); 
for (String element : someCollection) { 
.... 
} 
+1

Единственное, что вы теряете, используя эту форму итератора, это то, что вы не может вызвать метод Iterator.remove() - поскольку у вас нет ссылки на объект Iterator. –

+1

Верно .. но ты собираешься найти это довольно чертовски быстро! – tddmonkey

2

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

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

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

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

4

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

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

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

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

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

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

9

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

Когда вы объявляете 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 
}