Java 8 | how to initialize Map & List2Map gracefully

Keywords: Linux Operation & Maintenance network

The great Java 18 is coming out soon, and we may not be familiar with the core Lambda usage of Java 8. This article shares several tips for operating Map in the development process on Stream technology. After reading this article, I believe you will have a new understanding of Stream.

1, Gracefully initialize a Map

Before looking down, first think about how you would initialize a Map with initial values without the help of Apache common and other third-party packages. Think about it. Continue to look down. The code is roughly as shown in the following code.

final HashMap<String, String> maps = new HashMap<>();
maps.put("key1", "value1");
maps.put("key2", "value2");

The above methods can indeed initialize the Map, but the biggest problem is that we may need to change many lines to put key value pairs, which is very repetitive and wordy. In order to keep the code clean and give full play to the advantages of Java 8, we can actually use stream for initialization like the following code.

final HashMap<String, String> maps = Stream.of(new Object[][]{{"key1", "value1"}})
    .collect(Collectors.toMap(data -> (String) data[0], data -> (String) data[1]));

One line of code to complete the initialization of Map, does it need to be much more elegant. If you have used jooq Tuple, you will find that using Tuple will be more elegant and can accomplish more incredible things.

2, Gracefully List to Map

In the daily development process, in order to construct a specific data format for the front end, the back-end partners cannot avoid the need to convert List data into Map data. How would you complete this when you encounter such a problem? Generally speaking, the data conversion must be completed by traversal. But Java 8 has a Stream, which we can use to do something interesting.

Suppose we have a class Product, as shown in the following code.

@Getter
@Setter
@ToString
@Builder
class Product{
    private Long id;
    private String category;
    private String name;
}

We have now obtained the data in list < Product > format.

static List<Product> getList(){
    final List<Product> productList = new ArrayList<>(100);
    for(int i =1;i<=100;i++){
        productList.add(Product.builder()
            .id((long) i)
            .name("name"+i)
            .category("category"+i%9)
            .build());
    }
    return productList;
}

Now, we want to obtain the Map format data with id as key and name as value. The code is as follows.

Map<Long, String> map = productList.stream().collect(Collectors.toMap(Product::getId, Product::getName));

If you want to obtain Map format data with id as key and product as value, the code is as follows.

Map<Long, Product> map = productList.stream().collect(Collectors.toMap(Product::getId, data -> data));

If you want to obtain Map format data with category as key and name as value, the key may conflict. How to solve it? You need to pass in the key conflict resolution strategy. The code is as follows.

#When a conflict occurs, the pre-existing data is retained and can be customized according to the business
Map<String, String> map = productList.stream().collect(Collectors.toMap(Product::getCategory, Product::getName, (existing, replacement) -> existing));

If you want to finally obtain a thread safe Map, how to solve it? You need to pass in a supplier < m > mapsupplier. The code is as follows.

#Concurrent HashMap is introduced here. Similarly, it can also be implemented with TreeMap
ConcurrentHashMap<String, String> map = productList.stream().collect(Collectors.toMap(Product::getCategory, Product::getName, (existing, replacement) -> existing, ConcurrentHashMap::new));

Posted by cuteflower on Fri, 26 Nov 2021 08:43:41 -0800