Hola que tal. En este post les voy a mostrar que es eso de forEach y forEachOrdered que fueron introducidos en Java 8 para ayudarnos a hacer iteraciones sobre colecciones o incluso sobre streams.
Primero empecemos con forEach, el cual recibe solo un parámetro, una interface funcional, lo que significa que podemos pasarle una expresión lambda. Esa interface funcional debe ser consumer, que para los que no lo sepan, un consumer es una interface funcional que recibe un parámetro y no retorna nada. Veamos un ejemplo de como forEach nos ayuda para iterar sobre una colección, sobre una lista para ser mas precisos:
import java.util.ArrayList;
import java.util.List;
public class Ejemplo {
public static void main(String[] args) {
List<String> listadito = new ArrayList<>();
listadito.add("hola");
listadito.add("mundo");
listadito.add("cruel");
// usamos una expresion lambda y se la pasamos como parámetro
listadito.forEach(x -> System.out.println(x));
// La siguiente linea hace lo mismo que la anterior pero usamos method reference en vez de una expresión lambda
listadito.forEach(System.out::println);
}
}
El resultado del código anterior es el siguiente:
hola
mundo
cruel
hola
mundo
cruel
También es posible usar forEach en maps, sets y streams. A continuación un ejemplo:
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class Ejemplo {
public static void main(String[] args) {
// Ejemplo con Set
Set<String> mySet = new HashSet<>();
mySet.add("hola");
mySet.add("mundo");
mySet.add("cruel");
mySet.forEach(System.out::println);
// Ejemplo con Map
Map<Integer, String> myMap = new HashMap<>();
myMap.put(1, "hola");
myMap.put(2, "mundo");
myMap.put(3, "cruel");
myMap.forEach((x, y) -> System.out.println(x + " " + y));
// Ejemplo con Stream (reutilizamos el set que ya habia creado antes
mySet.stream()
.forEach(System.out::println);
}
}
La salida del ejemplo anterior puede variar ya que en los sets el orden de los elementos no esta garantizado, osea que el orden en que insertamos los valores dentro de un set puede que no sea el mismo que obtengamos al iterar sobre dichos valores. Dicho lo anterior, un posible resultado del ejemplo anterior seria lo siguiente:
hola
mundo
cruel
1 hola
2 mundo
3 cruel
hola
mundo
cruel
En el caso de los streams, el método forEach es un operador terminal, osea que es un operador que siempre va al final cuando se usa en un stream ya que no retorna nada después de su ejecución. Lo mismo ocurre para forEachOrdered.
Ahora veamos como usar forEachOrdered. Si lo que deseas es asegurar que los elementos de una lista, mapa, stream…. se ejecuten de manera en la que se encuentran o aparecen en dicha lista, mapa, stream… , hay que usar forEachOrdered, cabe notar que esto no funcionaria en el caso de un set porque los sets no tienen un orden de origen, así que en ese tipo de casos no aplicaría esto. A continuación un ejemplo en donde si aplicaría:
import java.util.Arrays;
import java.util.List;
public class Ejemplo {
public static void main(String[] args) {
List<String> myList = Arrays.asList("hola", "mundo", "cruel");
// Con forEach
myList.stream().parallel().forEach(System.out::println);
System.out.println("-------------------");
// Con forEachOrdered
myList.stream().parallel().forEachOrdered(System.out::println);
}
}
Podrás haber notado el uso de parallel(), con eso decimos que se ejecuten de manera paralela lo que sigue, que en este caso es el forEach ó forEachOrdered. Esto va a provocar que en el caso del forEach el orden de ejecución sea aleatorio, pero si usamos forEachOrdered el orden de ejecución sera el mismo que fue definido en la lista original. A continuación se muestra una posible salida del ejemplo anterior:
mundo
cruel
hola
-------------------
hola
mundo
cruel
Espero que encuentren este pequeño post útil para programar correctamente en Java. Saludos.