1. Antecedentes sobre cómo surgieron los iteradores
Ya estás familiarizado con HashSet
. Si realmente lo investigaste, más allá de solo leer una lección, entonces deberías haberte hecho esta pregunta:
¿Cómo muestro una lista de todos los elementos HashSet en la pantalla? ¡Después de todo, la interfaz no tiene get()
métodos set()
!
Y HashSet
no está solo en esta limitación. Además de HashSet
, hay muchas otras colecciones que no permiten recuperar elementos por índice, porque los elementos no tienen un orden definido.
A lo largo de los años, los programadores han inventado muchas estructuras de datos complejas, como gráficos y árboles. O listas de listas.
Muchos contenedores cambian el orden de sus elementos cuando se agregan elementos nuevos o se eliminan elementos existentes. Por ejemplo, una lista almacena elementos en un orden particular y cuando se agrega un nuevo elemento, casi siempre se inserta en el medio de la lista.
Y también tenemos situaciones en las que hay un contenedor que almacena elementos pero no en un orden fijo.
Ahora digamos que queremos copiar todos los elementos de dicha colección en una matriz o lista. Necesitamos conseguir todos los elementos. No nos importa el orden en el que iteramos sobre los elementos; lo importante es no iterar sobre los mismos elementos más de una vez. ¿Como hacemos eso?
2. Iterador para una colección
Se propusieron iteradores como una solución al problema anterior.
Un iterador es un objeto especial asociado con una colección, que ayuda a recorrer todos los elementos de la colección sin repetir ninguno.
Puede usar el siguiente código para obtener un iterador para cualquier colección:
Iterator<Type> it = name.iterator();
Donde name
es el nombre de la variable de colección, Type
es el tipo de los elementos de la colección, iterator()
es uno de los métodos de la colección y it
es el nombre de la variable iteradora.
Un objeto iterador tiene 3 métodos:
Método | Descripción |
---|---|
|
Devuelve el siguiente elemento de la colección. |
|
Comprueba si hay elementos que aún no se han recorrido |
|
Elimina el elemento actual de la colección. |
nextInt)
Estos métodos son algo similares a los métodos y de la clase Scanner hasNextInt()
.
El next()
método devuelve el siguiente elemento de la colección de la que obtuvimos el iterador.
El hasNext()
método verifica si la colección tiene elementos adicionales que el iterador aún no ha devuelto.
A continuación se explica cómo mostrar todos los elementos de un HashSet
:
Código | notas |
---|---|
|
Cree un HashSet objeto que almacene String elementos. Agregamos saludos en varios idiomas a la set variable. Obtenga un objeto iterador para el set conjunto. Mientras haya elementos Obtener el siguiente elemento Mostrar el elemento en la pantalla |
3. For-each
bucle
La principal desventaja de un iterador es que su código se vuelve más engorroso que usar un for
bucle.
Para comparar, mostremos una lista usando un for
bucle y también usando un iterador:
iterador | en bucle |
---|---|
|
|
Sí, es mucho mejor atravesar los elementos de un ArrayList
bucle usando un bucle: todo resulta ser más corto.
Pero los creadores de Java nuevamente decidieron echarnos un poco de azúcar. Por suerte para nosotros, era azúcar sintáctico .
Le dieron a Java un nuevo tipo de bucle y lo llamaron for-each
bucle. Así es como se ve en general:
for(Type name:collection)
Donde collection
es el nombre de la variable de la colección, Type
es el tipo de los elementos de la colección y name
es el nombre de una variable que toma el siguiente valor de la colección en cada iteración del ciclo.
Este tipo de bucle recorre en iteración todos los elementos de una colección mediante un iterador implícito. Así es como funciona en realidad:
Bucle para cada uno | Lo que ve el compilador: Bucle con un iterador |
---|---|
|
|
Cuando el compilador encuentra un for-each
bucle en su código, simplemente lo reemplaza con el código de la derecha: agrega una llamada para obtener un iterador junto con cualquier otra llamada de método faltante.
A los programadores les encanta el for-each
bucle y casi siempre lo usan cuando necesitan iterar sobre todos los elementos de una colección.
Incluso iterar sobre una ArrayList
lista usando un for-each
bucle parece más corto:
Bucle para cada uno | en bucle |
---|---|
|
|
4. Eliminar un elemento en un for-each
bucle
El for-each
bucle tiene un inconveniente: no puede eliminar elementos correctamente. Si escribe un código como este, obtendrá un error.
Código | Nota |
---|---|
|
¡La operación de eliminación generará un error! |
Este es un código muy agradable y comprensible, pero no funcionará.
No puede cambiar una colección mientras la recorre con un iterador.
Hay tres formas de sortear esta limitación.
1. Usa un tipo diferente de bucle
When traversing an ArrayList collection
, puede usar un ciclo ordinario con una i
variable de contador.
Código |
---|
|
Sin embargo, esta opción no es adecuada para HashSet
y HashMap
colecciones
2. Usa un iterador explícito
Puede usar un iterador explícitamente y llamar a su remove()
método.
Versión que funciona | Versión que no funciona |
---|---|
|
|
¡ Tenga en cuenta que llamamos al remove()
método en el objeto iterador! El iterador es consciente de que el elemento se ha eliminado y puede manejar la situación correctamente.
3. Usa una copia de la colección
También puede crear una copia de la colección y luego usar la copia en un for-each
bucle y eliminar elementos de la colección original.
Código | Nota |
---|---|
|
Crear una copia de una colección es muy fácil. El ciclo usa el iterador para la copia de la colección. Los elementos se eliminan de la list colección. |
La colección se copia con bastante rapidez, ya que los elementos en sí no se duplican. En cambio, la nueva colección almacena referencias a los elementos que ya existen en la colección anterior.