Map处理利器 - MapUtil JAVA开发 Map操作少不了,存储key-value键值对数据,常用来做缓存以及传输数据等,下面特别封装常用的方法 `MapUtil` 主要由下面部分组成:  ## 1 提取 方法 | Description :---- | :--------- **extractSubMap**(Map<K, O>, String) | 以参数 map的key为key,以参数 map value的指定`extractPropertyName`属性值为值,拼装成新的map返回. **extractSubMap**(Map<K, O>, K[], String) | 以参数 map的key为key,以参数 mapvalue的指定`extractPropertyName` 属性值为值,拼装成新的map返回. ### 1.1 extractSubMap(Map<K, O>, String) 以参数 map的key为key,以参数 map value的指定 `extractPropertyName` 属性值为值,拼装成新的map返回. **说明:** - 返回map的顺序,按照参数 map key的顺序 **示例:** ```JAVA Map<Long, User> map = new LinkedHashMap<>(); map.put(1L, new User(100L)); map.put(2L, new User(200L)); map.put(5L, new User(500L)); map.put(4L, new User(400L)); LOGGER.debug(JsonUtil.format(MapUtil.extractSubMap(map, "id"))); ``` **返回:** ```JSON { "1": 100, "2": 200, "5": 500, "4": 400 } ``` ### 1.2 extractSubMap(Map<K, O>, K[], String) 以参数 map的key为key,以参数 mapvalue的指定`extractPropertyName` 属性值为值,拼装成新的map返回. **说明:** - 如果在抽取的过程中,map没有某个 `includeKeys`,将会忽略该key的抽取,并输出 warn log - 如果参数 `includeKeys`是null或者 empty,那么会抽取map所有的key - 返回map的顺序,按照参数`includeKeys`的顺序(如果`includeKeys`是null,那么按照map key的顺序) **示例:** ```JAVA Map<Long, User> map = new LinkedHashMap<>(); map.put(1L, new User(100L)); map.put(2L, new User(200L)); map.put(53L, new User(300L)); map.put(5L, new User(500L)); map.put(6L, new User(600L)); map.put(4L, new User(400L)); Long[] includeKeys = { 5L, 4L }; LOGGER.debug(JsonUtil.format(MapUtil.extractSubMap(map, includeKeys, "id"))); ``` **返回:** ```JSON { "5": 500, "4": 400 } ``` **典型示例:** ```JAVA private Map<Long, Long> constructPropertyIdAndItemPropertiesIdMap( String properties, Map<Long, PropertyValueSubViewCommand> itemPropertiesIdAndPropertyValueSubViewCommandMap){ Long[] itemPropertiesIds = StoCommonUtil.toItemPropertiesIdLongs(properties); Map<Long, Long> itemPropertiesIdAndPropertyIdMap = MapUtil .extractSubMap(itemPropertiesIdAndPropertyValueSubViewCommandMap, itemPropertiesIds, "propertyId"); return MapUtil.invertMap(itemPropertiesIdAndPropertyIdMap); } ``` ## 2 获得子Map 方法 | Description :---- | :--------- **getSubMap**(Map<K, T>, K...) | 获得一个map 中的按照指定的key 整理成新的map. **getSubMapExcludeKeys**(Map<K, T>, K...) | 获得 sub map(去除不需要的keys). ### 2.1 getSubMap(Map<K, T>, K...) 获得一个map 中的按照指定的key 整理成新的map. **说明:** - 返回的map为 `LinkedHashMap`,key的顺序 按照参数 keys的顺序 - 如果循环的 key不在map key里面,则返回的map中忽略该key,并输出warn level log **示例:** ```JAVA Map<String, Integer> map = new HashMap<>(); map.put("a", 3007); map.put("b", 3001); map.put("c", 3001); map.put("d", 3003); LOGGER.debug(JsonUtil.format(MapUtil.getSubMap(map, "a", "c"))); ``` **返回:** ```JSON { "a": 3007, "c": 3001 } ``` ### 2.2 getSubMapExcludeKeys(Map<K, T>, K...) 获得 sub map(去除不需要的keys). **说明:** - 返回值为 `LinkedHashMap`,key的顺序 按照参数 map的顺序 - 如果 `excludeKeys`中含有 map 中不存在的key,将会输出warn级别的log **示例:** ```JAVA Map<String, Integer> map = new LinkedHashMap<>(); map.put("a", 3007); map.put("b", 3001); map.put("c", 3002); map.put("g", -1005); LOGGER.debug(JsonUtil.format(MapUtil.getSubMapExcludeKeys(map, "a", "g", "m"))); ``` **返回:** ```JSON { "b": 3001, "c": 3002 } ``` ## 3 构造 方法 | Description :---- | :--------- **newHashMap**(int) | 创建 `HashMap`实例,拥有足够的 `"initial capacity"` 应该控制expectedSize elements without growth. **newLinkedHashMap**(int) | 创建 `LinkedHashMap`实例,拥有足够的 `"initial capacity"` 应该控制expectedSize elements without growth. ### 3.1 newHashMap(int) 创建 `HashMap`实例,拥有足够的 `"initial capacity"` 应该控制expectedSize elements without growth. > This behavior cannot be broadly guaranteed, but it is observed to be true for OpenJDK 1.7. > It also can't be guaranteed that the method isn't inadvertently oversizing the returned map. **示例:** ```JAVA Map<String, String> newHashMap = MapUtil.newHashMap(3); newHashMap.put("name", "feilong"); newHashMap.put("age", "18"); newHashMap.put("address", "shanghai"); ``` **使用该方法的好处:** 1. **简化代码书写方式** 以前你可能需要这么写代码: ```JAVA Map<String, Map<Long, List<String>>> map = new HashMap<String, Map<Long, List<String>>>(16); ``` 如果你是使用JDK1.7或者以上,你可以使用钻石符: ```JAVA Map<String, Map<Long, List<String>>> map = new HashMap<>(16); ``` 不过只要你是使用1.5+,你都可以写成: ```JAVA Map<String, Map<Long, List<String>>> map = MapUtil.newHashMap(16); ``` 1. **减少扩容次数** 如果你要一次性初始一个能存放100个元素的map,并且不需要扩容,提高性能的话,你需要 ```JAVA Map<String, Map<Long, List<String>>> map = new HashMap<String, Map<Long, List<String>>>(100/0.75+1); ``` 使用这个方法,你可以直接写成: ```JAVA Map<String, Map<Long, List<String>>> map = MapUtil.newHashMap(100); ``` ### 3.2 newLinkedHashMap(int) 创建 `LinkedHashMap` 实例,拥有足够的 `"initial capacity"` 应该控制 `expectedSize elements without growth`. > This behavior cannot be broadly guaranteed, but it is observed to be true for OpenJDK 1.7. > It also can't be guaranteed that the method isn't inadvertently oversizing the returned map. **示例:** ```JAVA Map<String, String> map = MapUtil.newLinkedHashMap(3); map.put("name", "feilong"); map.put("age", "18"); map.put("address", "shanghai"); ``` **使用该方法的好处:** 1. **简化代码书写方式** 以前你可能需要这么写代码: ```JAVA Map<String, Map<Long, List<String>>> map = new LinkedHashMap<String, Map<Long, List<String>>>(16); ``` 如果你是使用JDK1.7或者以上,你可以使用钻石符: ```JAVA Map<String, Map<Long, List<String>>> map = new LinkedHashMap<>(16); ``` 不过只要你是使用1.5+,你都可以写成: ```JAVA Map<String, Map<Long, List<String>>> map = MapUtil.newLinkedHashMap(16); ``` 1. **减少扩容次数** 如果你要一次性初始一个能存放100个元素的map,并且不需要扩容,提高性能的话,你需要 ```JAVA Map<String, Map<Long, List<String>>> map = new LinkedHashMap<String, Map<Long, List<String>>>(100/0.75+1); ``` 使用这个方法,你可以直接写成: ```JAVA Map<String, Map<Long, List<String>>> map = MapUtil.newLinkedHashMap(100); ``` ## 4 辅助put 方法 | Description :---- | :--------- **putAllIfNotNull**(Map<K, V>, Map<? extends K, ? extends V>) | 仅当 `null != map` && `null != m`,才会进行 `map.putAll(m)` 操作 **putIfValueNotNull**(Map<K, V>, K, V)|仅当 `null != map` 并且 `null != value`才将key/value put到map中. **putIfValueNotNullOrEmpty**(Map<K, V>, K, V)|仅当 `null != map` 并且 `isNotNullOrEmpty(value)`才将key/value put到map中. **putMultiValue**(Map<K, List<V>>, K, V)|往 map 中put 指定 key value(多值形式). **putSumValue**(Map<K, Integer>, K, Integer)|将key和value 累加的形式put到 map中,如果map中存在key,那么累加value值;如果不存在那么直接put. ### 4.1 putIfValueNotNull(Map<K, V>, K, V) 仅当 `null != map` 并且 `null != value`才将key/value put到map中. **说明:** - 如果 map 是null,什么都不做 - 如果 value 是null,也什么都不做 - 如果 key 是null,依照map的key是否允许是null的 规则 ### 4.2 putAllIfNotNull(Map<K, V>, Map<? extends K, ? extends V>) 仅当 `null != map && null != m`,才会进行 `map.putAll(m)` 操作 **重构:** 对于以下代码: ```JAVA if (isNotNullOrEmpty(specialSignMap)){ map.putAll(specialSignMap); } ``` **可以重构成: ** ```JAVA MapUtil.putAllIfNotNull(map, specialSignMap) ``` ### 4.3 putIfValueNotNullOrEmpty(Map<K, V>, K, V) 仅当 `null != map` 并且 `isNotNullOrEmpty(value)`才将`key/value` put到map中. **说明:** - 如果 map 是null,什么都不做 - 如果 value 是null或者empty,也什么都不做 - 如果 key 是null,依照map的key是否允许是null的规则 **重构:** 对于以下代码: ```JAVA if (isNotNullOrEmpty(taoBaoOAuthLoginForCodeEntity.getState())){ nameAndValueMap.put("state", taoBaoOAuthLoginForCodeEntity.getState()); } ``` **可以重构成: ** ```JAVA MapUtil.putIfValueNotNullOrEmpty(nameAndValueMap, "state", taoBaoOAuthLoginForCodeEntity.getState()); ``` ### 4.4 putSumValue(Map<K, Integer>, K, Integer) 将key和value 累加的形式put到 map中,如果map中存在key,那么累加value值;如果不存在那么直接put. **示例:** ```JAVA Map<String, Integer> map = new HashMap<>(); MapUtil.putSumValue(map, "1000001", 5); MapUtil.putSumValue(map, "1000002", 5); MapUtil.putSumValue(map, "1000002", 5); LOGGER.debug(JsonUtil.format(map)); ``` **返回:** ```JSON { "1000001": 5, "1000002": 10 } ``` **重构:** 对于以下代码: ```JAVA if (disadvantageMap.containsKey(disadvantageToken)){ disadvantageMap.put(disadvantageToken, disadvantageMap.get(disadvantageToken) + 1); }else{ disadvantageMap.put(disadvantageToken, 1); } ``` **可以重构成:** ```JAVA MapUtil.putSumValue(disadvantageMap, disadvantageToken, 1); ``` ### 4.5 putMultiValue(Map<K, List<V>>, K, V) 往 map 中put 指定 key value(多值形式). **说明:** - map已经存在相同名称的key,那么value以list的形式累加. - 如果map中不存在指定名称的key,那么会构建一个ArrayList **示例:** ```JAVA Map<String, List<String>> mutiMap = newLinkedHashMap(2); MapUtil.putMultiValue(mutiMap, "name", "张飞"); MapUtil.putMultiValue(mutiMap, "name", "关羽"); MapUtil.putMultiValue(mutiMap, "age", "30"); LOGGER.debug(JsonUtil.format(mutiMap)); ``` **返回:** ```JSON { "name": [ "张飞", "关羽" ], "age": ["30"] } ``` 对于下面的代码: ```JAVA private void putItemToMap(Map<String, List<Item>> map,String tagName,Item item){ List<Item> itemList = map.get(tagName); if (isNullOrEmpty(itemList)){ itemList = new ArrayList<Item>(); } itemList.add(item); map.put(tagName, itemList); } ``` 可以重构成: ```JAVA private void putItemToMap(Map<String, List<Item>> map,String tagName,Item item){ com.feilong.core.util.MapUtil.putMultiValue(map, tagName, item); } ``` ## 5 删除 方法 | Description :---- | :--------- **removeKeys**(Map<K, V>, K...) | 删除 map 的指定的 keys. ### 5.1 removeKeys(Map<K, V>, K...) 删除 map 的指定的 keys. **注意** - 直接操作的是参数map,迭代 keys, - 如果 map包含key,那么直接调用 `Map.remove(Object)`, - 如果不包含,那么输出warn级别日志 **示例:** ```JAVA Map<String, String> map = newLinkedHashMap(3); map.put("name", "feilong"); map.put("age", "18"); map.put("country", "china"); LOGGER.debug(JsonUtil.format(MapUtil.removeKeys(map, "country"))); ``` **返回:** ```JSON { "name": "feilong", "age": "18" } ``` ## 6 转换 方法 | Description :---- | :--------- **toArrayValueMap**(Map<K, String>) | 将单值的`singleValueMap` 转成多值的map. **toSingleValueMap**(Map<K, V[]>) | 将多值的`arrayValueMap` 转成单值的map. ### 6.1 toSingleValueMap(Map<K, V[]>) 将多值的 `arrayValueMap` 转成单值的map. **示例1:** ```JAVA Map<String, String[]> arrayValueMap = new LinkedHashMap<>(); arrayValueMap.put("province", new String[] { "江苏省" }); arrayValueMap.put("city", new String[] { "南通市" }); LOGGER.info(JsonUtil.format(ParamUtil.toSingleValueMap(arrayValueMap))); ``` **返回:** ```JSON { "province": "江苏省", "city": "南通市" } ``` 如果 `arrayValueMap` 其中有key的值是多值的数组,那么转换到新的map中的时候,value取第一个值, **示例2:** ```JAVA Map<String, String[]> arrayValueMap = new LinkedHashMap<>(); arrayValueMap.put("province", new String[] { "浙江省", "江苏省" }); arrayValueMap.put("city", new String[] { "南通市" }); LOGGER.info(JsonUtil.format(ParamUtil.toSingleValueMap(arrayValueMap))); ``` **返回:** ```JSON { "province": "浙江省", "city": "南通市" } ``` **说明:** - 返回的map是 提取参数 `arrayValueMap`的key做为key,value数组的第一个元素做value - 返回的是 `LinkedHashMap`,保证顺序和参数 `arrayValueMap`顺序相同 - 和该方法正好相反的是 `toArrayValueMap(Map)` ### 6.2 toArrayValueMap(Map<K, String>) 将单值的 `singleValueMap` 转成多值的map. **示例:** ```JAVA Map<String, String> singleValueMap = new LinkedHashMap<>(); singleValueMap.put("province", "江苏省"); singleValueMap.put("city", "南通市"); LOGGER.info(JsonUtil.format(ParamUtil.toArrayValueMap(singleValueMap))); ``` **返回:** ```JSON { "province": ["江苏省"], "city": ["南通市"] } ``` **说明:** - 返回的是 `LinkedHashMap`,保证顺序和参数 `singleValueMap` 顺序相同 - 和该方法正好相反的是 `toSingleValueMap(Map)` ## 7 反转 方法 | Description :---- | :--------- **invertMap**(Map<K, V>) | ### 7.1 invertMap(Map<K, V>) 将 map 的key和value互转. **说明:** - 这个操作map预先良好的定义. - 如果传过来的map,不同的key有相同的value,那么返回的map(key)只会有一个(value),其他重复的key被丢掉了 **示例:** ```JAVA Map<String, Integer> map = new HashMap<>(); map.put("a", 3007); map.put("b", 3001); map.put("c", 3001); map.put("d", 3003); LOGGER.debug(JsonUtil.format(MapUtil.invertMap(map))); ``` **返回:** ```JSON { "3001": "c", "3007": "a", "3003": "d" } ``` 可以看出 b元素被覆盖了 ## 8.参考 - http://www.programcreek.com/2013/09/top-9-questions-for-java-map/