¿Por qué la Iterator
interfaz no se extiende?Iterable
?
El iterator()
método simplemente podría regresar this
.
¿Es a propósito o simplemente un descuido de los diseñadores de Java?
Sería conveniente poder usar un ciclo for-each con iteradores como este:
for(Object o : someContainer.listSomeObjects()) {
....
}
donde listSomeObjects()
devuelve un iterador.
Respuestas:
Porque un iterador generalmente apunta a una sola instancia en una colección. Iterable implica que uno puede obtener un iterador de un objeto para atravesar sus elementos, y no hay necesidad de iterar sobre una sola instancia, que es lo que representa un iterador.
fuente
Un iterador tiene estado. La idea es que si llama
Iterable.iterator()
dos veces obtendrá iteradores independientes , de todos modos para la mayoría de los iterables. Claramente, ese no sería el caso en su escenario.Por ejemplo, generalmente puedo escribir:
Eso debería imprimir la colección dos veces, pero con su esquema, el segundo ciclo siempre finalizaría instantáneamente.
fuente
iterator
y usa el resultado, tiene que iterar sobre la colección, lo que no hará si ese mismo objeto ya ha iterado sobre la colección. ¿Puede dar alguna implementación correcta (que no sea para una colección vacía) donde el mismo iterador se devuelve dos veces?iterable
dos veces le dará iteradores independientes.Por mis $ 0.02, estoy completamente de acuerdo en que Iterator no debe implementar Iterable, pero creo que el bucle mejorado también debería aceptar. Creo que todo el argumento "hacer iteradores iterables" surge como una solución a un defecto en el lenguaje.
Toda la razón para la introducción del bucle for mejorado fue que "elimina el trabajo pesado y la propensión a errores de los iteradores y las variables de índice al iterar sobre colecciones y matrices" [ 1 ].
¿Por qué entonces este mismo argumento no es válido para los iteradores?
En ambos casos, las llamadas a hasNext () y next () se han eliminado, y no hay ninguna referencia al iterador en el bucle interno. Sí, entiendo que los Iterables se pueden reutilizar para crear múltiples iteradores, pero que todo sucede fuera del ciclo for: dentro del ciclo solo hay una progresión hacia adelante un elemento a la vez sobre los elementos devueltos por el iterador.
Además, permitir esto también facilitaría el uso del bucle for para Enumeraciones, que, como se ha señalado en otra parte, son análogos a Iteradores, no Iterables.
Por lo tanto, no haga que Iterator implemente Iterable, pero actualice el bucle for para aceptar tampoco.
Salud,
fuente
for(item : iter) {...}
sintaxis, provocará un error cuando el mismo iterador se repita dos veces. Imagine queIterator
se pasa aliterateOver
método en lugar deIterable
en este ejemplo .for (String x : strings) {...}
owhile (strings.hasNext()) {...}
: si intenta recorrer un iterador dos veces la segunda vez no obtendrá resultados, por lo que no lo veo en sí mismo como un argumento en contra de permitir la sintaxis mejorada. La respuesta de Jon es diferente, porque allí está mostrando cómo envolver unaIterator
en unaIterable
causaría problemas, ya que en ese caso esperarías poder reutilizarla tantas veces como quisieras.Como señalaron otros,
Iterator
yIterable
son dos cosas diferentes.Además, las
Iterator
implementaciones son anteriores a los bucles.También es trivial superar esta limitación con un método de adaptador simple que se ve así cuando se usa con importaciones de métodos estáticos:
Implementación de muestra:
En Java 8, adaptar una
Iterator
a una seIterable
vuelve más simple:fuente
for (String s : (Iterable<String>) () -> iterator)
Como otros han dicho, un Iterable se puede llamar varias veces, devolviendo un nuevo iterador en cada llamada; un iterador se usa solo una vez. Entonces están relacionados, pero tienen diferentes propósitos. Sin embargo, frustrantemente, el método "compacto para" funciona solo con un iterable.
Lo que describiré a continuación es una forma de tener lo mejor de ambos mundos: devolver un Iterable (para una sintaxis más agradable) incluso cuando la secuencia de datos subyacente es única.
El truco consiste en devolver una implementación anónima de Iterable que realmente active el trabajo. Entonces, en lugar de hacer el trabajo que genera una secuencia única y luego devolver un iterador sobre eso, devuelve un Iterable que, cada vez que se accede, vuelve a hacer el trabajo. Puede parecer un desperdicio, pero a menudo solo llamarás al Iterable de todos modos, e incluso si lo llamas varias veces, todavía tiene una semántica razonable (a diferencia de un contenedor simple que hace que un Iterador "parezca" un Iterable, esto ganó ' t falla si se usa dos veces).
Por ejemplo, supongamos que tengo un DAO que proporciona una serie de objetos de una base de datos y quiero proporcionar acceso a eso a través de un iterador (por ejemplo, para evitar crear todos los objetos en la memoria si no son necesarios). Ahora podría devolver un iterador, pero eso hace que usar el valor devuelto en un bucle sea feo. Entonces, en cambio, envuelvo todo en un anon Iterable:
Esto se puede usar en un código como este:
lo que me permite usar el bucle compacto para mantener el uso de memoria incremental.
Este enfoque es "vago": el trabajo no se realiza cuando se solicita el Iterable, sino solo más tarde cuando se repite el contenido, y debe ser consciente de las consecuencias de eso. En el ejemplo con un DAO que significa iterar sobre los resultados dentro de la transacción de la base de datos.
Así que hay varias advertencias, pero esto puede ser una expresión útil en muchos casos.
fuente
returning a fresh Iterator on each call
debe ir acompañado de por qué esto es para evitar la emisión de concurrencia ...Increíblemente, nadie más ha dado esta respuesta todavía. A continuación, le mostramos cómo puede iterar "fácilmente" sobre una
Iterator
mediante el nuevoIterator.forEachRemaining()
método Java 8 :Por supuesto, hay una solución "más simple" que funciona con el bucle foreach directamente, envolviendo el
Iterator
en unaIterable
lambda:fuente
Iterator
es una interfaz que te permite iterar sobre algo. Es una implementación de moverse a través de una colección de algún tipo.Iterable
es una interfaz funcional que denota que algo contiene un iterador accesible.En Java8, esto hace la vida bastante fácil ... Si tiene un
Iterator
pero necesitaIterable
uno, simplemente puede hacer:Esto también funciona en el ciclo for:
fuente
Estoy de acuerdo con la respuesta aceptada, pero quiero agregar mi propia explicación.
El iterador representa el estado de desplazamiento, por ejemplo, puede obtener el elemento actual de un iterador y avanzar al siguiente.
Iterable representa una colección que podría atravesarse, puede devolver tantos iteradores como desee, cada uno representando su propio estado de desplazamiento, un iterador puede estar apuntando al primer elemento, mientras que otro puede estar apuntando al tercer elemento.
Sería bueno si Java for loop acepta tanto Iterator como Iterable.
fuente
Para evitar la dependencia del
java.util
paqueteDe acuerdo con el JSR original, un bucle mejorado para el lenguaje de programación Java ™ , las interfaces propuestas:
java.lang.Iterable
java.lang.ReadOnlyIterator
(se propuso adaptarlo
java.util.Iterator
, pero aparentemente esto nunca sucedió)... fueron diseñados para usar el
java.lang
espacio de nombres del paquete en lugar dejava.util
.Para citar el JSR:
Por cierto, el viejo
java.util.Iterable
ganó un nuevoforEach
método en Java 8+, para usar con la sintaxis lambda (pasando aConsumer
).Aquí hay un ejemplo. La
List
interfaz extiende laIterable
interfaz, ya que cualquier lista lleva unforEach
método.fuente
También veo a muchos haciendo esto:
¡Pero eso no lo hace correcto! ¡Este método no sería lo que quieres!
Se
iterator()
supone que el método devuelve un nuevo iterador a partir de cero. Entonces uno necesita hacer algo como esto:La pregunta es: ¿habría alguna forma de hacer que una clase abstracta realice esto? Para obtener un IterableIterator solo es necesario implementar los dos métodos next () y hasNext ()
fuente
Si vino aquí en busca de una solución alternativa, puede usar IteratorIterable . (disponible para Java 1.6 y superior)
Ejemplo de uso (invertir un vector).
huellas dactilares
fuente
En aras de la simplicidad, Iterador e Iterable son dos conceptos distintos, Iterable es simplemente una abreviatura de "Puedo devolver un Iterador". Creo que tu código debería ser:
con alguna instancia de Contenedor
SomeContainer extends Iterable<Object>
fuente
Como un aparte: Scala tiene un método toIterable () en Iterator. Vea la conversión implícita o explícita de escala de iterador a iterable
fuente
En una nota relacionada, puede encontrar útil el adaptador IteratorIterable en Apache Commons Collections4. Simplemente cree una instancia desde un iterador y tendrá el iterable correspondiente.
https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/iterators/IteratorIterable.html
ID: org.apache.commons: commons-collections4: 4.0
fuente
Los iteradores tienen estado, tienen un elemento "siguiente" y se "agotan" una vez que se repiten. Para ver dónde está el problema, ejecute el siguiente código, ¿cuántos números se imprimen?
fuente
Puedes probar el siguiente ejemplo:
fuente