Let's look at the code below. I create a Product class that contains a list of Items.
@Value
@Builder
public class Product {
long productId;
List<Item> items;
@Value
@Builder
public static class Item {
long itemId;
}
}
And then I get the product list using an external API. In order to handle item objects, I use a nested for loop.
I make itemsByItemId
Map object. Key is itemId and value is item object.
public class Main {
public static void main(String[] args) {
// get product list using an external api
ApiClient apiClient = new ApiClient();
List<Product> products = apiClient.getProducts().collectList().block();
Map<Long, Item> itemsByItemId = new HashMap<>();
for (Product product : products) {
for (Item item : product.getItems()) {
itemsByItemId.put(item.getItemId(), item);
}
}
System.out.println(itemsByItemId);
}
}
However I want to use java stream api. Let's look at the code below. It looks complicated at a glance.
For each item, we create and merge Maps using Map.of, and since we need to merge again at the product level, we incorporate flatMap(map -> map.entrySet().stream())
and collect(Collectors.toMap)
twice each.
public class Main {
public static void main(String[] args) {
// get product list using an external api
ApiClient apiClient = new ApiClient();
List<Product> products = apiClient.getProducts().collectList().block();
Map<Long, Item> itemsByItemId = products.stream() // Stream<Product>
.map(product ->
product.getItems().stream() // Stream<Item>
.map(item ->
Map.of(item.getItemId(), item)) // Stream<Map<Long, Item>>
.flatMap(map -> map.entrySet().stream()) // Stream<Entry<Long, Item>>
.collect(Collectors.toMap(
Entry::getKey,
Entry::getValue,
(item1, item2) -> item2
)
)
) // Stream<Map<Long, Item>>
.flatMap(map -> map.entrySet().stream()) // Stream<Entry<Long, Item>>
.collect(Collectors.toMap(
Entry::getKey,
Entry::getValue,
(item1, item2) -> item2
)
);
System.out.println(itemsByItemId);
}
}
This is a better solution code. I create item lists using flatMap. .flatMap(product -> product.getItems().stream())
And then, I only need to create them once with Map.of
.
public class Main {
public static void main(String[] args) {
// get product list using an external api
ApiClient apiClient = new ApiClient();
List<Product> products = apiClient.getProducts().collectList().block();
Map<Long, Item> itemsByItemId = products.stream() // Stream<Product>
.flatMap(product -> product.getItems().stream()) // Stream<Item>
.map(item -> Map.of(item.getItemId(), item)) // Stream<Map<Long, Item>>
.flatMap(map -> map.entrySet().stream()) // Stream<Entry<Long, Item>>
.collect(Collectors.toMap(
Entry::getKey,
Entry::getValue,
(item1, item2) -> item2
)
);
System.out.println(itemsByItemId);
}
}
However, in reality, since collect(Collectors.toMap)
is used to create the Map, there's no need for me to manually work with Map.of
. Ultimately, it resulted in much simpler code as shown below.
public class Main {
public static void main(String[] args) {
// get product list using an external api
ApiClient apiClient = new ApiClient();
List<Product> products = apiClient.getProducts().collectList().block();
Map<Long, Item> itemsByItemId = products.stream() // Stream<Product>
.flatMap(product -> product.getItems().stream()) // Stream<Item>
.collect(Collectors.toMap(Item::getItemId, Function.identity()));
System.out.println(itemsByItemId);
}
}
Top comments (0)