开发利器Hutool之MapUtil的使用

一、概述

1.1 工具简介

  MapUtil 是 Hutool 中用于简化 Map 操作的工具类,它封装了大量静态方法,统一封装 Map 的创建、判断、转换、过滤、排序、合并、遍历等高频操作,替代冗长的原生 JDK 模板代码,减少重复、降低出错率。

1.2 引入依赖

  在使用Hutool工具之前,我们需要将Hutool添加到项目的依赖中。如果使用Maven构建项目,可以在 pom.xml 文件中添加以下依赖:

xml 复制代码
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <!-- 请检查最新版本,可以根据实际需要进行调整 -->
    <version>5.8.40</version>
</dependency>

  Hutool-all 是一个 Hutool 的集成打包产品,由于考虑到"懒人"用户及分不清各个模块作用的用户,"无脑"引入 hutool-all 模块是快速开始和深入应用的最佳方式。如果你想像 SpringBoot 一样引入 Hutool,再由子模块决定用到哪些模块,你可以在父模块中加入:

xml 复制代码
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-bom</artifactId>
            <version>${hutool.version}</version>
            <type>pom</type>
            <!-- 注意这里是import -->
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

  然后再在子模块中就可以引入自己需要的模块了:

xml 复制代码
<dependencies>
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-core</artifactId>
    </dependency>
</dependencies>

二、Map 创建与初始化

2.1 链式构建 builder

  builder 是 Hutool 的建造者模式链式构建 Map,底层返回 MapBuilder 对象,告别多次 new HashMap + 多次 put,代码更简洁,常用于接口参数组装、返回结果封装、测试构造数据。

方法 简要说明
builder() 空构建器,默认底层是 HashMap
builder(K k, V v) 初始化携带一个键值对
builder(Map<K,V> map) 基于已有Map继续追加put(包装原有Map)

  返回值都是 MapBuilder,支持链式调用。

方法 简要说明
put(K key, V value) 添加键值对,返回自身,支持链式
putAll(Map map) 批量加入另一个 Map 全部元素
build() 构建返回 Map 实例(默认 HashMap,可修改)
buildImmutable() 返回的 Map 不能新增、修改、删除 key,适合常量、返回结果防止外部篡改
java 复制代码
// 简单用法
MapUtil.builder().put("name", "张三").put("age", 22).build();

// 使用 builder 链式创建,非常直观
Map<String, Object> params = MapUtil.builder(new HashMap<String, Object>())
        .put("appId", "123456")
        .put("timestamp", System.currentTimeMillis())
        .build();

// builder 带初始键值对
MapUtil.builder("count", 100).put("total", 200).build();

// 基于已有 Map 追加元素
MapUtil.builder(MapUtil.of("a", "1")).put("b", "2").build();

2.2 快捷填充 of

  由键值对数组创建,适合快速构造小规模的键值对

方法 返回类型 简要说明
of(K key, V value) HashMap 创建单个键值对的 HashMap
of(K key, V value, boolean isOrder) HashMap LinkedHashMap 单个键值对,isOrder=true 返回 LinkedHashMap,保留插入顺序
of(Object\[\] array) HashMap<Object,Object> 二维字符串数组构建 Map
ofEntries(Map.Entry... entries) 根据 Entry 数组创建 Map
java 复制代码
// 单个键值对
Map<String, String> single = MapUtil.of("key", "value");

// 二维数组构建
Map<Object, Object> colors = MapUtil.of(new String[][]{
        {"RED", "#FF0000"},
        {"GREEN", "#00FF00"}
});

Map<String,Integer> map = MapUtil.ofEntries(
        Map.entry("a",1),
        Map.entry("b",2)
);

2.3 快速创建

方法 返回类型 简要说明
newConcurrentHashMap() ConcurrentHashMap 无参创建线程安全 Map,并发场景使用
newConcurrentHashMap(int size) ConcurrentHashMap 指定初始容量
newConcurrentHashMap(Map map) ConcurrentHashMap
newHashMap() HashMap 新建空HashMap,无序
newHashMap(boolean isLinked) HashMap LinkedHashMap isLinked=true 返回 LinkedHashMap,保插入序
newHashMap(int size) HashMap 指定初始容量,避免扩容(最多装 size 个)
newHashMap(int size, boolean isLinked) 指定初始容量、是否有序
newIdentityMap(int size) Map 按引用相等判 key
newTreeMap(Comparator comparator) TreeMap 自定义排序规则建 Map
newTreeMap(Map map, Comparator comparator) TreeMap 已有 Map + 规则
createMap(Class mapType) Map 反射创建任意 Map 实现类
java 复制代码
// 普通hashmap
Map<String, Object> hashMap = MapUtil.newHashMap(5);
hashMap.put("a", 1);
hashMap.put("b", 2);

// LinkedHashMap 有序
Map<String, Object> linkedMap = MapUtil.newHashMap(5, true);
linkedMap.put("z", 1);
linkedMap.put("a", 2);
System.out.println(linkedMap);

// TreeMap 按键排序
TreeMap<String, Integer> treeMap = MapUtil.newTreeMap(Comparator.reverseOrder());
treeMap.put("a", 1);
treeMap.put("b", 2);
System.out.println(treeMap); // {b=2,a=1}

// 并发安全map
ConcurrentHashMap<String, Object> concurrentMap = MapUtil.newConcurrentHashMap(10);
concurrentMap.put("k1", "v1");

三、Map 基础操作

3.1 判空与空值处理

  处理 Map 的第一步,永远是先看看这个 Map 靠不靠谱。一个 null 的 Map,或者一个空的 Map,如果不加判断就直接操作,NullPointerException 就是"见面礼",MapUtils 给了我们几把趁手的"安检仪"。

方法 简要说明
isEmpty(Map) 判断 Map 为 null 或无元素
isNotEmpty(Map) 判断 Map 非空,用在需要 Map 有内容时才执行操作的场景
emptyIfNull 如果传入的map为null,就返回一个空的、不可变的EmptyMap对象,否则原样返回
defaultIfEmpty 若 Map 为空则返回默认 Map
empty() 返回一个空 Map
java 复制代码
Map<String, Object> map = null;

System.out.println("Map 是否为空:" + MapUtil.isEmpty(map));
System.out.println("Map 是否不为空:" + MapUtil.isNotEmpty(map));

// null 安全:返回不可变空 Map,后续可放心遍历
Map<String, Object> safe = MapUtil.emptyIfNull(map);

// 为空则给默认值
Map<String, Object> queryResult = null;
Map<String, Object> fallbackMap = null;
Map<String, Object> data = MapUtil.defaultIfEmpty(queryResult, fallbackMap);

3.2 安全取值

  这是 MapUtil 最实用的部分------直接从 Map 里取出指定类型,支持自动类型转换和默认值。如果 key 不存在或转换失败,通常返回 null 或默认值。提供默认值这个功能,看似简单,实则极大地提升了代码的鲁棒性,特别是在处理配置项或者非必填的用户输入时。

方法 简要说明
getStr(Map map, Object key) 取字符串值
getStr(Map map, Object key, Boolean defaultValue) 取字符串值
getAny(Map map, K... keys) 从原 Map 中提取指定的键值对,生成一个新的 map
java 复制代码
Map<String, Object> user = MapUtil.<String, Object>builder()  
        .put("name", "张三")  
        .put("age", "18")          // 注意:字符串  
        .put("balance", "99.50")  
        .put("vip", "true")  
        .put("loginTime", "2024-05-01 12:30:00")  
        .build();  
  
String name    = MapUtil.getStr(user, "name");
Integer age    = MapUtil.getInt(user, "age");
Long    uid    = MapUtil.getLong(user, "uid");
Double  bal    = MapUtil.getDouble(user, "balance");
Boolean vip    = MapUtil.getBool(user, "vip");
Date    login  = MapUtil.getDate(user, "loginTime");

Map<String,Object> origin = MapUtil.of("id",1,"name","hutool","status",1);
Map<String,Object> subMap = MapUtil.getAny(origin, "id", "name");

3.3 获取指定类型

  对于自定义对象或泛型集合,可以使用 get 配合 Class 或 TypeReference。

方法 简要说明
get(Map map, Object key, Class type) 泛型类型转换,复杂对象
get(Map map, Object key, Class type, T defaultValue)
get(Map map, Object key, TypeReference type)
get(Map map, Object key, TypeReference type, T defaultValue)
java 复制代码
// 获取 User 对象
User user = MapUtil.get(map, "user", User.class);

// 获取 List<String>(利用 TypeReference 保留泛型信息)
List<String> tags = MapUtil.get(map, "tags", new TypeReference<List<String>>() {});

3.4 Map 元素操作

方法 简要说明
clear(Map... maps) 批量清空多个 map
removeAny(Map map, K... keys) 移除指定 key(修改原 Map)
removeNullValue(Map map) 移除 value 为 null 的项
renameKey(Map map, K oldKey, K newKey) 重命名 key,将旧 key 的值迁移到新 key
java 复制代码
MapUtil.removeAny(map, "a", "c");        // 移除指定 key(修改原 Map)
MapUtil.removeNullValue(map);            // 移除 value 为 null 的项

四、Map 进阶操作

4.1 Map 排序

方法 简要说明
sort(Map map) 按 key 升序排序,返回新 Map,不修改原对象
sort(Map map, Comparato comparator) 按自定义比较器排序
sortByValue(Map map, boolean isDesc) 按 value 排序,可选是否倒序,返回新 Map,不修改原对象
java 复制代码
@Test
public void sortTest() {
    Map<String, Integer> score = MapUtil.newHashMap();
    score.put("Chinese", 88);
    score.put("Math", 95);
    score.put("English", 70);

    // 按 key 自然顺序排序(返回新 Map,原 Map 不变)
    Map<String, Integer> byKey = MapUtil.sort(score);
    System.out.println(byKey);

    // 按 key 自定义比较器
    Map<String, Integer> byKeyDesc = MapUtil.sort(score, Comparator.reverseOrder());
    System.out.println(byKeyDesc);
}

@Test
public void sortByValueTest() {
    Map<String, String> map = MapUtil.newHashMap();
    map.put("a", "1");
    map.put("b", "2");
    map.put("c", "1");
    // 排序, 不会改变原来的值
    Map<String, String> newMap = MapUtil.sortByValue(map, true);
    System.out.println(newMap);
}

4.2 map 拼接字符串

方法 简要说明
join(map, separator, keyValueSeparator, isIgnoreNull) join(map, separator, keyValueSeparator, isIgnoreNull,otherParams) 将map转成字符串,按遍历顺序拼接,顺序取决于 Map 实现
joinIgnoreNull(map, separator, keyValueSeparator,otherParams) 将map转成字符串,忽略null的键和值
sortJoin(map, separator, keyValueSeparator, isIgnoreNull,otherParams) 根据参数排序后拼接为字符串,常用于接口参数签名

参数含义:

方法 简要说明
Map map 待拼接的 Map
String separator 条目之间的分隔符
String keyValueSeparator key 与 value 之间的分隔符
boolean isIgnoreNull 是否忽略 null 键或值
String... otherParams 可变参数,拼在最后(通常放 appSecret)
java 复制代码
Map<String, String> params = MapUtil.builder(new HashMap<String, String>())
        .put("key1", "value1")
        .put("key3", "value3")
        .put("key2", "value2")
        .build();
String str01 = MapUtil.join(params, "&", "=");
System.out.println(str01);

// sortJoin:先按 key 排序再拼接 ------ 签名就用这个
String str02 = MapUtil.sortJoin(params, StrUtil.EMPTY, StrUtil.EMPTY, false);
System.out.println(str02);

// sortJoin 带尾部密钥
String str03 = MapUtil.sortJoin(params, "&", "=", false, "SECRET_KEY");
System.out.println(str03);

// joinIgnoreNull:跳过 null 的 key 和 value
String str04 = MapUtil.joinIgnoreNull(params, "&", "=");
System.out.println(str04);

4.3 filter 筛选元素

  传入一个 Filter 实现,只保留满足条件的 Entry

方法 简要说明
filter(Map map, K... keys) 过滤Map保留指定键值对,如果键不存在跳过
filter(Map map, Filter filter) 自定义过滤,保留满足条件的元素,返回新 Map
java 复制代码
Map<String, String> map = MapUtil.newHashMap();
map.put("a", "1");
map.put("b", "2");
map.put("c", "3");
map.put("d", "4");
// 过滤出被2整除的数据
Map<String, String> map2 = MapUtil.filter(map, t -> Convert.toInt(t.getValue()) % 2 == 0);
System.out.println(map2);

五、Map 转换操作

5.1 键值互换

方法 简要说明
inverse(Map map) 键值互换,注意 value 重复会覆盖,在需要根据值反向查找键的时候特别有用

✅ 如果原 Map 有重复 value ,互换后会发生覆盖,条目数变少。反转前先确认 value 唯一,或者改用 Map<K, List<V>> 结构。

java 复制代码
@Test
public void inverseTest() {
    Map<String, String> map = MapUtil.newHashMap();
    map.put("a", "1");
    map.put("b", "2");
    map.put("c", "1");
    System.out.println("键值互换之前:" + map);
    Map<String, String> inverse = MapUtil.inverse(map);
    System.out.println("键值互换之后:" + inverse);
}

@Test
public void invertMapTest() {
    // 错误码映射
    Map<Integer, String> errorCodeMap = new HashMap<>();
    errorCodeMap.put(404, "Not Found");
    errorCodeMap.put(500, "Internal Server Error");
    errorCodeMap.put(200, "Success");

    // 反向查找:通过错误信息找错误码
    Map<String, Integer> invertedMap = MapUtil.inverse(errorCodeMap);

    String receivedMessage = "Internal Server Error";
    Integer possibleErrorCode = invertedMap.get(receivedMessage);
    if (possibleErrorCode != null) {
        System.out.println("对应的错误码是: " + possibleErrorCode); // 输出 500
    }
}

5.2 行列转换

  大家是不是遇到过将多个 map 以 key 进行分组,然后相同 key 下的 value 合并成一个 list 的场景,现在可以通过下面的行列互转的方式轻松解决。

方法 简要说明 备注
toListMap(Iterable mapList) 行转列,按相同的 key 进行分组,把 value 合并成一个 List 生成新 Map
toMapList(Map listMap) 列转行,将键值对为 List 的 Map 还原为 Map 列表 生成新 Map
java 复制代码
@Test
public void toListMapTest() {
    Map<String, String> map1 = MapUtil.of("a", "1");
    Map<String, String> map2 = MapUtil.of("a", "5");
    Map<String, String> map3 = MapUtil.of("b", "4");
    Map<String, String> map4 = MapUtil.of("a", "5");
    List<Map<String, String>> maps = ListUtil.of(map1, map2, map3, map4);
    System.out.println("toListMap: " + MapUtil.toListMap(maps));
}

@Test
public void toMapListTest() {
    Map<String, List<Integer>> cols = MapUtil.newHashMap(true);
    cols.put("a", List.of(1, 2, 3, 4));
    cols.put("b", List.of(1, 2, 3));
    cols.put("c", List.of(1));

    List<Map<String, Integer>> rows = MapUtil.toMapList(cols);
    System.out.println(rows);
}

5.3 结构变换

方法 作用 是否原地修改
grouping(Iterable entries) 按 entry 的 key 分组,值聚合成 List 新 Map
toCamelCaseMap(Map map) key 下划线转驼峰 新 Map
toObjectArray(Map map) Map → 二维数组 新数组
valuesOfKeys(Map map, Iterator keys) 批量按 key 取值,返回 List(缺则 null) 新 List
partition(Map, int size) 大 Map 按大小切分为多个小HashMap 新 List
flatten(Map) 多层嵌套 Map 摊平为一层(递归) 新 Map
map(Map map, BiFunction biFunction) 使用 BiFunction 对每个 Entry 进行转换 新 Map
java 复制代码
MapUtil.partition(MapUtil.of(new Object[][]{{"a",1},{"b",2},{"c",3}}), 2);  

Map<String, Object> nested = MapUtil.<String,Object>builder()
        .put("k", 1)
        .put("sub", MapUtil.of("x", 2))
        .build();
MapUtil.flatten(nested);   // → {x=2, k=1}

Map<String, String> map = MapUtil.newHashMap();
map.put("a", "1");
map.put("b", "2");
Map<String, String> result = MapUtil.map(map, (k, v) -> k.toUpperCase() + "-" + v);
System.out.println(result);
相关推荐
水墨长天1 小时前
物联网协议 MQTT 快速开发与实践
后端·物联网
GreenTea1 小时前
深度拆解 ScienceBuddy:如何用“双层递归自进化”构建高可靠科研 Agent Harness
前端·后端·算法
IT_陈寒1 小时前
React组件意外更新的罪魁祸首,我排查了这一整天
前端·人工智能·后端
子兮曰1 小时前
Laya 深度解析:421M 开源决策模型硬刚 Jev,33ms 背后藏了啥
前端·后端·python
子兮曰1 小时前
1.3亿月活还不够,DeepSeek这次直接把饭碗端走了
前端·后端·aigc
知守观1 小时前
我用 Executors 创建线程池,被阿里规约第一页打了脸——老项目并发踩坑实录
后端
卷无止境1 小时前
前沿部署工程师:当代码写到客户的办公室里
后端·python
lizhongxuan1 小时前
Agent Sandbox:Firecracker 运行路径与安全边界
后端
海岳云舟1 小时前
简易规则引擎 easy-rules
后端