En este articulo veras como convertir un list a un map utilizando para ello un Stream disponible desde Java 8.
¿Cómo convertir un List a un Map?
Partiendo de una lista de productos creamos un Stream
public class Product {
private long id;
private String name;
private String type;
private Double price;
public Product() {
}
public Product(long id, String name, String type, double price) {
this.id = id;
this.name = name;
this.type = type;
this.price = price;
}
//...
@Override
public String toString() {
return "Product{" +
"id=" + id +
", name='" + name + '\'' +
", type='" + type + '\'' +
", price=" + price +
'}';
}
}
Creamos un Stream a partir de la lista de productos:
List<Product> productList = new ArrayList<>();
productList.add(new Product(1, "SONY", "TV", 100));
productList.add(new Product(2, "SAMSUNG", "MOBILE", 200));
Stream<Product> productStream = productList.stream();
Usar Collectors.toMap para crear un map
Luego haces uso del Stream y “Collectors.toMap” en donde para este ejemplo usamos el id del producto como key del mapa y el nombre como valor.
// Stream to Map with Collectors.toMap
Map<Long, String> productMap = productStream.collect(Collectors.toMap(Product::getId, Product::getName));
productMap.forEach((k,v)->System.out.println("key : " + k + " value : " + v));
// output:
// key : 1 value : SONY
// key : 2 value : SAMSUNG
// key : 3 value : LG
Usar Function.identity() para guardar el objeto en el value del mapa
Si deseas usar como valor el mismo objeto puedes hacer uso de Function.identity() para el value
Map<Long, Product> productMapObject = productList.stream().collect(Collectors.toMap(Product::getId, Function.identity()));
// output
// key : 1 value : Product{id=1, name='SONY', type='TV', price=100.0}
// key : 2 value : Product{id=2, name='SAMSUNG', type='MOBILE', price=200.0}
// key : 3 value : Product{id=3, name='LG', type='MOBILE', price=300.0}
Evitando Duplicate key
Si en en la lista y por consiguiente en el Stream tienes dos elementos con un mismo id recibirás un IllegalStateException al tratar de crear el mapa.
// Exception
productList.add(new Product(2, "SAMSUNG DUPLICATE", "MOBILE", 200));
try {
Map<Long, String> productMapError = productList.stream().collect(Collectors.toMap(Product::getId, Product::getName));
} catch (IllegalStateException e) {
e.printStackTrace();
}
El error de salida es confuso porque muestra el valor del mapa en vez de mostrar el key que se duplica.
Exception in thread "main" java.lang.IllegalStateException: Duplicate key SAMSUNG
//..
Para resolver esto pasas una función que realice el tratamiento de los duplicados para evitar este error:
// handle duplicate ids
Map<Long, String> list =
productStream
.collect(Collectors.toMap(
Product::getId,
Product::getName,
(oldValue, newValue) -> oldValue
));
// output:
// key : 1 value : SONY
// key : 2 value : SAMSUNG
// key : 3 value : LG
Básicamente lo que haces es decidir entre los dos valores duplicados con cual deseas quedarte. (oldValue, newValue) -> oldValue
Creando un mapa ordenado
Para crear un mapa ordenado solo debes indicarle al Stream el ordenamiento que deseas pasándole el comparador que deseas, en este ejemplo ordenamos con el key (id del producto).
// creating a ordered map
Map orderMap = productList.stream()
.sorted(Comparator.comparingLong(Product::getId).reversed())
.collect(
Collectors.toMap(
Product::getId, Product::getName,
(oldValue, newValue) -> oldValue, // if duplicate
LinkedHashMap::new // use LinkedHashMap to keep order
));
orderMap.forEach((k, v) -> System.out.println("key : " + k + " value : " + v));
// output:
// key : 3 value : LG
// key : 2 value : SAMSUNG
// key : 1 value : SONY
Conclusión: usando Stream para colectar el resultado con Collectors.toMap creas un mapa a partir de tu lista.
Luego puedes evitar duplicados pasándole una función para decidir qué hacer en caso de encontrarse con un key duplicado. .