ListValueMap
# 功能介绍
ListValueMap是Hutool中MultiValueMap接口的List实现类,它允许一个键对应多个值,并且值以List形式存储。与普通Map不同,ListValueMap的put方法不会覆盖已有键的值,而是将新值添加到该键对应的List中,同时保持插入顺序,允许重复值。
# 主要特性
- 支持一个键对应多个值,值以List形式存储
- 保持插入顺序,值的顺序与添加顺序一致
- 允许重复值,同一个键可以添加相同的值多次
- 基于HashMap实现,性能优异
- 支持所有MultiValueMap接口方法
- 支持null键和null值
- 线程不安全,建议在单线程环境下使用
- 支持与普通Map的相互转换
# 适用场景
- 需要保持值插入顺序的多值映射场景
- 允许重复值的多值映射场景
- 处理HTTP请求参数(同一个参数名可能有多个值)
- 处理表单提交(多个复选框可能提交同一个字段名)
- 实现标签系统(一个内容可以有多个标签,允许重复标签)
- 任何需要一个键关联多个有序值的场景
# 使用示例
# 示例1:基本用法
// 创建ListValueMap实例
ListValueMap<String, String> listValueMap = new ListValueMap<>();
// 添加键值对,同一个键可以添加多个值
listValueMap.put("tag", "java");
listValueMap.put("tag", "tool");
listValueMap.put("tag", "util");
listValueMap.put("tag", "java"); // 允许重复值
listValueMap.put("author", "looly");
// 获取单个值(返回第一个值)
String firstTag = listValueMap.getFirst("tag");
// 输出: java
// 获取值集合(List形式,保持插入顺序)
List<String> tags = listValueMap.get("tag");
// 输出: [java, tool, util, java]
// 遍历所有键值对
listValueMap.forEach((key, values) -> {
Console.log(key + ": " + values);
});
// 输出:
// tag: [java, tool, util, java]
// author: [looly]
# 示例2:添加和删除值
ListValueMap<String, String> listValueMap = new ListValueMap<>();
listValueMap.put("tag", "java");
listValueMap.put("tag", "tool");
listValueMap.put("tag", "util");
// 添加单个值
listValueMap.add("tag", "library");
// 此时tag的值集合: [java, tool, util, library]
// 添加多个值
listValueMap.addAll("tag", ListUtil.of("framework", "opensource"));
// 此时tag的值集合: [java, tool, util, library, framework, opensource]
// 删除指定键的指定值(删除第一个匹配的值)
listValueMap.remove("tag", "tool");
// 此时tag的值集合: [java, util, library, framework, opensource]
// 删除指定键的所有值
listValueMap.removeAll("tag");
// 此时tag的值集合: []
# 示例3:转换为普通Map
ListValueMap<String, String> listValueMap = new ListValueMap<>();
listValueMap.put("tag", "java");
listValueMap.put("tag", "tool");
listValueMap.put("author", "looly");
// 转换为普通Map,值为List
Map<String, List<String>> normalMap = listValueMap.toMap();
// 转换为普通Map,值为第一个值
Map<String, String> firstValueMap = listValueMap.toMap(false);
// 输出
Console.log(normalMap);
// 输出: {tag=[java, tool], author=[looly]}
Console.log(firstValueMap);
// 输出: {tag=java, author=looly}
# 示例4:遍历所有键值对
ListValueMap<String, String> listValueMap = new ListValueMap<>();
listValueMap.put("tag", "java");
listValueMap.put("tag", "tool");
listValueMap.put("author", "looly");
// 遍历所有键值集合对
listValueMap.forEach((key, values) -> {
Console.log(key + ": " + values);
});
// 输出:
// tag: [java, tool]
// author: [looly]
// 遍历所有键值对(包括每个值)
listValueMap.forEachEntry((key, value) -> {
Console.log(key + "=" + value);
});
// 输出:
// tag=java
// tag=tool
// author=looly
# 注意事项
- ListValueMap是线程不安全的,在多线程环境下使用需要额外同步
- 保持插入顺序,值的顺序与添加顺序一致
- 允许重复值,同一个键可以添加相同的值多次
get()方法返回的是值的List,而不是单个值getFirst()方法返回键对应的第一个值put()方法不会覆盖已有值,而是添加到值List中- 支持null键和null值,null值也会被添加到List中
- 性能与HashMap相当,适合大多数场景
- 可以通过构造函数指定底层List的实现类
# 方法列表
ListValueMap实现了MultiValueMap接口,因此支持所有MultiValueMap方法,主要包括:
| 方法名 | 描述 | 参数 | 返回值 |
|---|---|---|---|
| ListValueMap() | 创建默认的ListValueMap | 无 | 无 |
| ListValueMap(Map<K, List | 使用已有Map创建ListValueMap | map: 已有Map | 无 |
| ListValueMap(Supplier<List | 指定List实现类创建ListValueMap | listSupplier: List工厂 | 无 |
| put(K key, V value) | 添加键值对,将值添加到List中 | key: 键, value: 值 | List |
| add(K key, V value) | 添加单个值到指定键 | key: 键, value: 值 | void |
| addAll(K key, Collection | 添加多个值到指定键 | key: 键, values: 值集合 | void |
| get(K key) | 获取键对应的值List | key: 键 | List |
| getFirst(K key) | 获取键对应的第一个值 | key: 键 | V |
| remove(K key, V value) | 删除键对应的指定值(删除第一个匹配的值) | key: 键, value: 值 | boolean |
| removeAll(K key) | 删除键对应的所有值 | key: 键 | List |
| clear() | 清空所有键值对 | 无 | void |
| size() | 获取键值对总数(每个值算一个键值对) | 无 | int |
| keySize() | 获取不同键的数量 | 无 | int |
| containsKey(K key) | 判断是否包含指定键 | key: 键 | boolean |
| containsValue(K key, V value) | 判断键是否包含指定值 | key: 键, value: 值 | boolean |
| keySet() | 获取所有键的集合 | 无 | Set |
| values() | 获取所有值List的集合 | 无 | Collection<List |
| forEach(BiConsumer<? super K, ? super List | 遍历所有键值List对 | action: 遍历操作 | void |
| forEachEntry(BiConsumer<? super K, ? super V> action) | 遍历所有键值对(包括每个值) | action: 遍历操作 | void |
| toMap() | 转换为普通Map,值为List | 无 | Map<K, List |
| toMap(boolean singleValue) | 转换为普通Map,singleValue为true时只取第一个值 | singleValue: 是否只取第一个值 | Map<K, ?> |