2009-02-05 17 views
15

Cuando utilizo un iterador de objetos utilizo un bucle while (como está escrito en todos los libros de aprendizaje de Java, como Pensando en Java de Bruce Eckel) :diferencia entre mover un iterador hacia adelante con una instrucción y una declaración mientras

Iterator it=... 

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

pero en algún lugar vi que alguien utilice el bucle for:

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

yo no' entiende esta elección:

  • Puedo utilizar el bucle for cuando tengo una colección con secuencia ordinal (como array) o con una regla especial para el paso (declarado generalmente como un simple incremento counter++).
  • Uso el mientras que el bucle cuando el bucle termina con No he tenido estas restricciones, pero solo una condición lógica para salir.

Es una cuestión de estilo de codificación sin otra causa o existe alguna otra lógica (rendimiento, por ejemplo) que yo no' sé?

Gracias por todos los comentarios

+0

No es un ejemplo de la conversión de 'Iterator' a compatibles con for-each loop 'Iterable' en http://stackoverflow.com/questions/2598219/java-why-cant-iterate-over-an-iterator/ – Vadzim

Respuesta

32

La sintaxis correcta para el bucle for es:

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

(La declaración anterior en el código es superfluo, así como el punto y coma adicional en el encabezado for loop.)

Tanto si usa esta sintaxis como si el while es una cuestión de gusto, ambos se traducen exactamente de la misma manera. La sintaxis genérica del bucle for es:

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

que es equivalente a:

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

Editar: En realidad, las dos formas anteriores no son totalmente equivalentes, si (como en el pregunta) la variable se declara con la instrucción init. En este caso, habrá una diferencia en el alcance de la variable del iterador. Con el bucle for, el alcance se limita al bucle en sí, en el caso del bucle while, sin embargo, el alcance se extiende hasta el final del bloque envolvente (no es de extrañar, ya que la declaración está fuera del bucle).

También, como otros han señalado, en las últimas versiones de Java, no es una notación abreviada para el bucle for:

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

se puede escribir como:

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

Con este formulario , por supuesto, perderá la referencia directa al iterador, que es necesario, por ejemplo, si desea eliminar elementos de la colección mientras itera.

+0

Si agrega las referencias al alcance limitado obtenido del uso de un bucle "for", esta es la respuesta perfecta ... –

+0

@Michael: Ahí lo tiene. –

9

Es sólo una cosa de estilo y al igual que yo prefiero el bucle cuando se utiliza algo con un índice. Si está utilizando Java 5 se debe utilizar, por supuesto, un bucle foreach sobre la colección de todos modos:

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

Lo único que pierde al usar esta forma de iterador es que usted no puede llamar al método Iterator.remove(), ya que no tiene referencia al objeto Iterator. –

+1

Cierto ... ¡pero vas a descubrirlo muy rápido! – tddmonkey

2

Las personas pueden usar el bucle explícito ('estilo antiguo') simplemente porque les parece más limpio, quizás aún no se hayan ajustado a la nueva sintaxis (que personalmente considero que es mucho más limpio).

Una ventaja específica real de la construcción de bucle más larga es que tiene una referencia al iterador y, por lo tanto, puede llamar a otros métodos distintos de next(). En particular, hasNext() a menudo puede ser útil para llamar - imaginar si desea imprimir una lista de cadenas separadas por comas:

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

Es sólo para distinguir el "este es el último" caso como este, si utiliza el bucle más detallado para.

4

No hay mucha diferencia entre esos dos métodos, excepto el primero que recuerda el valor de it después del bucle. El segundo enfoque probablemente arroje un error, porque redeclaras la variable dentro del ciclo.

En realidad, hay un tercer método para esto. En lugar de escribir, p.

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

se puede escribir más a menudo

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

Estos dos iguales a la misma cosa ...

9

El propósito de declarar la Iterator dentro del bucle for es minimizar el alcance de sus variables, que es una buena práctica.

Cuando declara el Iterator fuera del ciclo, la referencia sigue siendo válida/activa después de que finalice el ciclo. 99,99% de las veces, no es necesario seguir utilizando el Iterator una vez que el bucle se completa, por lo que un estilo de este tipo puede conducir a errores como este:

//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 
} 
Cuestiones relacionadas