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