La API de Streams en Java 8 permite transformar colecciones List en Map mediante Collectors.toMap. Este método es versátil, pero requiere atención a posibles errores como claves duplicadas o valores nulos. A continuación, se detallan ejemplos y estrategias para abordar estos escenariso.
Conversión básica de List a Map
Supongamos una lista de objetos Employee que se desea mapear por su identificador. El código siguiente realiza la conversión simple:
List<Employee> staffList = new ArrayList<>();
staffList.add(new Employee("EMP101", "Ana Martínez"));
staffList.add(new Employee("EMP102", "Luis Rodríguez"));
staffList.add(new Employee("EMP103", "Elena Sánchez"));
Map<String, String> idToNameMap = staffList.stream()
.collect(Collectors.toMap(Employee::getEmpId, Employee::getFullName));
Este enfoque genera un mapa donde las claves son los IDs de los empleados y los valores sus nombres completos. Sin embargo, si existen claves repetidas, se producirá una excepción IllegalStateException por clave duplicada.
Manejo de claves duplicadas
Para resolver conflictos con claves duplicadas, se pueden aplicar diferentes estrategias según las necesidades del negocio.
Sobrescribir el valor existente: Mantener el último valor procesado.
Map<String, String> overwritableMap = staffList.stream()
.collect(Collectors.toMap(
Employee::getEmpId,
Employee::getFullName,
(existingValue, newValue) -> newValue
));
Concatenar valores: Unir los valores de claves idénticas con un separaodr.
Map<String, String> concatenatedMap = staffList.stream()
.collect(Collectors.toMap(
Employee::getEmpId,
Employee::getFullName,
(v1, v2) -> v1 + "," + v2
));
Agrupar en listas: Recolectar múltiples valores para una misma clave en una lista.
Map<String, List<String>> groupedMap = staffList.stream()
.collect(Collectors.toMap(
Employee::getEmpId,
emp -> {
List<String> names = new ArrayList<>();
names.add(emp.getFullName());
return names;
},
(list1, list2) -> {
list1.addAll(list2);
return list1;
}
));
Prevención de NullPointerException con valores nulos
Si algún valor del objeto es null, Collectors.toMap puede fallar con una NullPointerException. Para manejar esto, se puede usar la técnica de agrupación en listas, ya que permite incluir valores nulos de forma segura.
Map<String, List<String>> nullSafeMap = staffList.stream()
.collect(Collectors.toMap(
Employee::getEmpId,
emp -> {
List<String> nameList = new ArrayList<>();
nameList.add(emp.getFullName()); // Incluso si getFullName() es null, se agrega
return nameList;
},
(listA, listB) -> {
listA.addAll(listB);
return listA;
}
));
Este método garantiza que la transformación se complete sin errores, almacenando tanto valores válidos como nulos en las listas correspondientes.