En Java, el bucle for-each simplifica el proceso transversal de cualquier colección o matriz, pero no todos los programadores de Java conocen algunos de los detalles del bucle for-each que se describirán en este artículo. A diferencia de otros términos publicados en Java 5: genéricos publicados con alias, encapsulación automática y parámetros variados, los desarrolladores de Java utilizan bucles for-each con más frecuencia que cualquier otra característica, pero cuando se les pregunta qué tan avanzados funcionan los bucles for-each o cuáles son los básicos. requisitos al usar una Colección en un bucle para cada uno, no todos pueden responderlo.
Este tutorial y ejemplo tienen como objetivo llenar ese vacío profundizando en algunos acertijos interesantes en bucles for-each. Bien, no entremos en detalles, echemos un vistazo a nuestro primer problema con el bucle for-each de Java5.
Pregunta 1 del bucle avanzado
Considere el siguiente código que atraviesa un agregador o clase de colección definido por el usuario. Qué imprimirá este código, ya sea que genere una excepción o un error del compilador:
Copie el código de código de la siguiente manera:
prueba de paquete;
/**
* Clase Java para mostrar cómo funciona el bucle for-each en Java
*/
clase pública para cada prueba {
principal vacío estático público (String args []) {
CustomCollection<String> myCollection = nueva CustomCollection<String>();
miCollection.add("Java");
miCollection.add("Scala");
miCollection.add("Maravilloso");
// ¿Qué hará este código? Idioma impreso, generar excepción o error en tiempo de compilación.
for(Idioma de cadena: miColección){
System.out.println(idioma);
}
}
}
A continuación se muestra nuestra clase CustomCollection, que es una clase genérica que, como cualquier otra clase de Colección, se basa en una ArrayList y proporciona métodos para agregar y eliminar elementos de la Colección.
Copie el código de código de la siguiente manera:
prueba de paquete;
clase pública Colección personalizada<T>{
depósito privado ArrayList<T>;
Colección personalizada pública(){
depósito = nueva ArrayList();
}
tamaño int público() {
devolver cubo.tamaño();
}
público booleano está vacío() {
devolver cubo.isEmpty();
}
booleano público contiene (T o) {
devolver cubo.contiene(o);
}
agregar booleano público (T e) {
devolver cubo.add(e);
}
eliminar booleano público (T o) {
devolver cubo.remove(o);
}
}
Respuesta:
El código anterior no se compilará porque nuestra clase CustomCollection no implementa la interfaz java.lang.Iterable. El error en tiempo de compilación es el siguiente:
Copie el código de código de la siguiente manera:
Excepción en el hilo "principal" java.lang.RuntimeException: código fuente no compilable - para cada uno no aplicable al tipo de expresión
requerido: matriz o java.lang.Iterable
encontrado: prueba.CustomCollection
en test.ForEachTest.main(ForEachTest.java:24)
Un hecho interesante que se puede aprender de esto es que el bucle for-each solo se aplica a las clases de matriz y colección de Java que implementan la interfaz Iterable, y dado que todas las clases de colección integradas implementan la interfaz java.util.Collection y han heredado Iterable, esto Un detalle que a menudo se pasa por alto se puede ver en la declaración de tipo de la interfaz de la Colección "la colección de interfaz pública extiende Iterable". Entonces, para resolver el problema anterior, puede optar por simplemente dejar que CustomCollection implemente la interfaz Collection o heredar AbstractCollection, que es la implementación universal predeterminada y muestra cómo usar clases e interfaces abstractas al mismo tiempo para una mayor flexibilidad. Ahora veamos el segundo acertijo del bucle for-each:
La segunda dificultad con los bucles Java para cada uno:
El siguiente ejemplo de código generará una excepción ConcurrentModificationException. Aquí usamos un iterador estándar y un bucle for-each para iterar a través de ArrayList y luego eliminar los elementos. Necesita averiguar qué fragmento de código generará ConcurrentModificationException y por qué. Tenga en cuenta que la respuesta podría ser ambas, ninguna, una u otra.
Copie el código de código de la siguiente manera:
prueba de paquete;
importar java.util.ArrayList;
importar java.util.Collection;
importar java.util.Iterator;
/**
* Clase Java para demostrar el funcionamiento interno del bucle for-each en Java
*@autor Javin Pablo
**/
clase pública para cada prueba2 {
principal vacío estático público (String args []) {
Colección<String> lista = nueva ArrayList<String>();
lista.add("Android");
lista.add("iPhone");
lista.add("Windows Mobile");
// ¿Qué código arrojará ConcurrentModificationException, ambos?
// ninguno o uno de ellos
// ejemplo 1
Iterador<Cadena> itr = lista.iterador();
mientras(itr.hasNext()){
Idioma de cadena = itr.next();
lista.remove(idioma);
}
//ejemplo 2
for(Idioma de cadena: lista){
lista.remove(idioma);
}
}
}
Aproximadamente el 70% de los desarrolladores de Java dirán que el primer bloque de código generará una excepción ConcurrentModificationException porque no usamos el método remove del iterador para eliminar elementos, sino que usamos el método remove() de ArrayList. Sin embargo, no muchos desarrolladores de Java dirían que ocurre el mismo problema con el bucle for-each, ya que aquí no utilizamos el iterador. De hecho, el segundo fragmento de código también arroja una excepción ConcurrentModificationException, que se vuelve obvia después de resolver la primera confusión. Dado que el bucle for-each utiliza un iterador internamente para recorrer la colección, también llama a Iterator.next(), que comprueba si hay cambios (de elementos) y genera una excepción ConcurrentModificationException. Puede ver esto en el resultado a continuación, que obtiene cuando ejecuta el segundo fragmento después de comentar el primer fragmento.
Copie el código de código de la siguiente manera:
Excepción en el hilo "principal" java.util.ConcurrentModificationException
en java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
en java.util.AbstractList$Itr.next(AbstractList.java:343)
en test.ForEachTest2.main(ForEachTest2.java:34)
Se trata del bucle Java5 para cada uno. Hemos visto muchos problemas que tienen los programadores de Java al escribir código para iterar sobre una clase Colección, especialmente cuando iteran sobre una colección mientras eliminan elementos al mismo tiempo. Recuerde usar siempre el método remove del Iterador al eliminar objetos de cualquier Colección (como un Mapa, Conjunto o Lista). Recuerde también que el bucle for-each es solo azúcar sintáctico (azúcar sintáctico) además del uso estándar del. código de iterador estándar) únicamente.
Nota del traductor: El azúcar sintáctico, también traducido como gramática recubierta de azúcar, es un término inventado por el informático británico Peter J. Landin, que se refiere a un cierto tipo de gramática agregada a los lenguajes informáticos. La sintaxis no tiene ningún impacto en la funcionalidad del. lenguaje, pero lo hace más fácil de usar para los programadores. En términos generales, el uso de azúcar de sintaxis puede aumentar la legibilidad del programa, reduciendo así la posibilidad de errores en el código del programa.