Al ser algo nuevo en el lenguaje Java, estoy tratando de familiarizarme con todas las formas (o al menos las no patológicas) que uno podría recorrer en iteración a través de una lista (o quizás otras colecciones) y las ventajas o desventajas de cada una.
Dado un List<E> list
objeto, conozco las siguientes formas de recorrer todos los elementos:
Básico para bucle (por supuesto, también hay bucles while
/ equivalentes do while
)
// Not recommended (see below)!
for (int i = 0; i < list.size(); i++) {
E element = list.get(i);
// 1 - can call methods of element
// 2 - can use 'i' to make index-based calls to methods of list
// ...
}
Nota: Como señaló @amarseillan, este formulario es una mala elección para iterar sobre List
s, porque la implementación real del get
método puede no ser tan eficiente como cuando se usa un Iterator
. Por ejemplo,LinkedList
implementaciones deben atravesar todos los elementos que preceden a i para obtener el elemento i-ésimo.
En el ejemplo anterior, no hay forma de que la List
implementación "guarde su lugar" para que las iteraciones futuras sean más eficientes. Para un ArrayList
no importa realmente, porque la complejidad / costo de get
es tiempo constante (O (1)) mientras que para a LinkedList
es proporcional al tamaño de la lista (O (n)).
Para obtener más información sobre la complejidad computacional de las Collections
implementaciones integradas , consulte esta pregunta .
Mejorado para bucle (bien explicado en esta pregunta )
for (E element : list) {
// 1 - can call methods of element
// ...
}
Iterador
for (Iterator<E> iter = list.iterator(); iter.hasNext(); ) {
E element = iter.next();
// 1 - can call methods of element
// 2 - can use iter.remove() to remove the current element from the list
// ...
}
ListIterator
for (ListIterator<E> iter = list.listIterator(); iter.hasNext(); ) {
E element = iter.next();
// 1 - can call methods of element
// 2 - can use iter.remove() to remove the current element from the list
// 3 - can use iter.add(...) to insert a new element into the list
// between element and iter->next()
// 4 - can use iter.set(...) to replace the current element
// ...
}
Java funcional
list.stream().map(e -> e + 1); // Can apply a transformation function for e
Iterable.forEach , Stream.forEach , ...
(Un método de mapa de la API Stream de Java 8 (consulte la respuesta de @ i_am_zero)).
En Java 8, las clases de colección que implementan Iterable
(por ejemplo, todas las List
s) ahora tienen un forEach
método, que se puede utilizar en lugar de la instrucción for loop mostrada anteriormente. (Aquí hay otra pregunta que proporciona una buena comparación).
Arrays.asList(1,2,3,4).forEach(System.out::println);
// 1 - can call methods of an element
// 2 - would need reference to containing object to remove an item
// (TODO: someone please confirm / deny this)
// 3 - functionally separates iteration from the action
// being performed with each item.
Arrays.asList(1,2,3,4).stream().forEach(System.out::println);
// Same capabilities as above plus potentially greater
// utilization of parallelism
// (caution: consequently, order of execution is not guaranteed,
// see [Stream.forEachOrdered][stream-foreach-ordered] for more
// information about this).
¿Qué otras formas hay, si hay alguna?
(Por cierto, mi interés no proviene en absoluto del deseo de optimizar el rendimiento ; solo quiero saber qué formularios están disponibles para mí como desarrollador).
List
interfaz específicamente?