This is the 25th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021
preface
Although I say I don’t recommend using Map as an interface parameter, I actually use it, really… Smells good. Let me talk about the pit we encountered when using Map as an interface parameter and why we used Map as an interface parameter.
First of all, we have to admit that Map can be fully inclusive, all parameters, all kinds of parameters can be directly put in the Map, so it is very convenient, the interface does not need to change, new parameters do not worry, add at any time. It’s very flexible. It also scales very well. But it’s very difficult to maintain, because there are things in the Map that you can’t read until you look at the code, and there are some type conversion bugs, which I’ll focus on below.
The Long type is converted to Integer
Map is serialized and deserialized when it is passed between microservices as an interface parameter. The problem is that deserialization converts a value of type Long to Integer (if it is in the int range). Let me give you an example.
// service 1 Map<String, Object> Map = new HashMap<>(); Long age = 18; map.put("age", age); feignClient.transfer(map); Transfer (Map<String, Object> Map){Long age = (Long) map.get("age"); }Copy the code
The first problem is that when a value of type Long is passed from one service to another, the type information changes from Long to Integer. The second problem is that null-pointer exceptions can occur. If map.get(“age”) is empty, an error will be reported here.
The Date type is converted to Long
Go straight to the code, so you can see it
// 服务 1
Map<String, Object> map = new HashMap<>();
Date date = new Date();
map.put("date", date);
feignClient.transfer(map);
// 服务 2
transfer(Map<String, Object> map){
Long timeLong = map.get("date");
Date date = new Date(timeLong);
}
Copy the code
If 1 map.put(” Date “, null), if 1 map.put(” Date “, null), if 1 map.put(” Date “, null), In service 2, an error is reported, and we need to manually nullify it.
Code not maintainable
In the example above, we can also feel the convenience of using map as interface parameters. However, there are more problems with hard code. Who can know the key in map? If you use this key today, you may not use it tomorrow. Can you understand? Even if you know the key, do you still need an empty judgment. This one down, is to write when the high maintenance of the time scold niang.
Wouldn’t it be better if we used Object, whether DTO or TO, as an argument and could wrap any argument in a class? Spring and Hibernate provide a validator with some annotations that can be used elegantly to validate data. One problem, however, is that the object needs to change constantly because the type or number of arguments may change.
conclusion
Using a map to pass parameters is not recommended unless it is absolutely necessary. You can create a class that encapsulates the parameters. The benefits are obvious: the code is readable, it looks clean, the type definition is clear, and if you want to add new parameters, you simply add them to the class. You can also define getter setter methods in the class, which is more comfortable to use.
To use a map, you need to know all the keys and their types. If the map is unfortunately used at multiple levels, these keys need to be known at each level… Map is great to write, but there is a good chance that it will have some problems when running.
Finally, why do we use maps? There are too many keys… And the number of keys is always uncertain, so map is used first.