2010-04-08 17 views

Respuesta

7

pero sigo sin entender por qué este [...] no fue posible.

puedo ver varias razones:

  1. Iterator s no son reutilizables, por lo que una de/cada consumirían el iterador - comportamiento no incorrecta, tal vez, pero poco intuitivo para los que no saben cómo el for/each está desacreditado.
  2. Iterator s no aparecen "desnudos" en el código con demasiada frecuencia, por lo que complicaría el JLS con poca ganancia (el constructo for/each es lo suficientemente malo como está, trabajando tanto en Iterable s como en matrices).
  3. Hay un easy workaround. Puede parecer un poco inútil asignar un nuevo objeto solo para esto, pero la asignación es barata y el análisis de escape le libraría incluso de ese pequeño costo en la mayoría de los casos. (¿Por qué no incluyeron esta solución en una clase de utilidad Iterables, análoga a Collections y Arrays, está más allá de mí, sin embargo.)
  4. (probablemente no es cierto -. Ver los comentarios) Me parece recordar que el JLS puede solo referencia cosas en java.lang[cita requerida], por lo que tendrían que crear una interfaz Iterator en java.lang que java.util.Iterator se extiende sin agregar nada a. Ahora tenemos dos interfaces de iterador funcionalmente equivalentes. El 50% del nuevo código que usa iteradores desnudos elegirá la versión java.lang, el resto usará el de java.util. Continúa el caos, abundan los problemas de compatibilidad, etc.

Creo puntos 1-3 son muy de acuerdo con la forma en la filosofía de diseño del lenguaje Java parece ir: No sorprenda a los recién llegados, no complicar la especificación si no tiene una ganancia clara que eclipsa los costos, y no funciona con una función de idioma, qué se puede hacer con una biblioteca.

Los mismos argumentos explican por qué java.util.Enumeration no es Iterable, también.

+0

"Me parece recordar que el JLS solo puede hacer referencia a cosas en java.lang" Ignorando cualquier contexto de 'discusión' o 'ejemplo' (del que hay muchos), el JLS se refiere varias veces a java.io.Serializable (§4.10.3 y otros) como un caso especial (por ejemplo, Serializable es un supertipo válido de una matriz primitiva). Irrelevante para la discusión en cuestión, pero interesante de todos modos. – Cowan

+0

No hay 'java.util.Enumerator'. ¿Querías decir 'Enumeración'? –

+0

@Cowan, gracias. Incluso miré el JLS pero logré perder esas partes. @Joachim, lo hice. Actualicé mi publicación. – gustafc

17

más probable es que la razón de esto se debe a que los iteradores no son reutilizables; necesita obtener un iterador nuevo de la colección Iterable cada vez que quiera iterar sobre los elementos. Sin embargo, como una solución rápida:

private static <T> Iterable<T> iterable(final Iterator<T> it){ 
    return new Iterable<T>(){ public Iterator<T> iterator(){ return it; } }; 
} 

//.... 
{ 
    // ... 
    // Now we can use: 
    for (X x : iterable(it)){ 
     // do something with x 
    } 
    // ... 
} 
//.... 

Dicho esto, lo mejor que puede hacer es simplemente pasar alrededor de la interfaz de Iterable<T> en lugar de Iterator<T>

+0

+1: con matrices y 'Iterable' puede escribir el mismo bucle dos veces seguidas y lo han trabajar como se espera Eso no funciona con 'Iterator'. –

+0

Tienes razón, sería mejor, pero estoy usando mi propio iterador sobre algo que no es una Colección real (es una Lista de nodos DOM). De lo contrario, su respuesta tiene sentido, gracias. – noamtm

+5

@noamtm: si no es una 'Colección' pero puede proporcionar un' Iterator', entonces probablemente debería implementar 'Iterable'. –

6

La sintaxis for(Type t : iterable) sólo es válida para las clases que implementan Iterable<Type>.

Un iterador no implementa iterable.

Puede repetir cosas como Collection<T>, List<T> o Set<T> porque implementan Iterable.

El código siguiente es equivalente:

for (Type t: list) { 
    // do something with t 
} 

y

Iterator<Type> iter = list.iterator(); 
while (iter.hasNext()) { 
    t = iter.next(); 
    // do something with t 
} 

La razón de que esto no fue posible, se debe a la cada de la sintaxis se añadió a la lengua de abstraer la Iterator . Hacer que el bucle for-each funcione con iteradores no lograría para qué se creó el bucle for-each.

+3

Eso es obvio, no responde mi pregunta de "por qué no fue posible". – noamtm

+1

Un 'Mapa' (que sería' Map ', btw) no * implementa *' Iterable'. Tendría que usar 'keySet()', 'values ​​()' o 'entrySet()' e iterar sobre esos. –

+0

@Joach Mi mal, estaba pensando en C#. – jjnguy

2

Los iteradores no se deben reutilizar (es decir, se usan en más de un bucle de iteración). En particular, Iterator.hasNext() garantiza que puede llamar de manera segura al Iterator.next() y, de hecho, obtener el siguiente valor de la colección subyacente.

Cuando se utiliza el mismo repetidor en dos iteraciones se ejecutan simultáneamente (vamos a suponer un escenario de múltiples hilos), esta promesa ya no puede mantenerse:

while(iter.hasNext() { 
    // Now a context switch happens, another thread is performing 
    // iter.hasNext(); x = iter.next(); 

    String s = iter.next(); 
      // A runtime exception is thrown because the iterator was 
      // exhausted by the other thread 
} 

Tales escenarios se rompen por completo el protocolo ofrecido por iterador. En realidad, pueden ocurrir incluso en un único programa de subprocesos: un ciclo de iteración llama a otro método que usa el mismo iterador para realizar su propia iteración. Cuando este método retorna, la persona que llama está emitiendo una llamada Iterator.next() que, nuevamente, falla.

0

Debido a que el para-cada uno está diseñado para leer como algo parecido a:

for each element of [some collection of elements] 

Un Iterator no es [some collection of elements]. Una matriz y un Iterable es.

3

En realidad, puedes.

Hay muy poca solución disponible en java 8:

for (X item : (Iterable<X>)() -> iterator) 

Ver How to iterate with foreach loop over java 8 stream para la explicación detallada del truco.

Y algunas explicaciones de por qué esto no fue apoyado de forma nativa se pueden encontrar en cuestión conexa:

Why does Stream<T> not implement Iterable<T>?

+0

Gracias, pero realmente no responde mi pregunta. La pregunta (de 2010) fue realmente sobre la elección del diseño (de ahí "por qué", no "cómo"). +1 porque es bueno saberlo, sin embargo. – noamtm