1. 简介
日常开发中使用Map时经常会遇到很多复杂的处理场景,例如:多个键的Map、不仅可以根据键获取值也可以根据值获取键且不用遍历、重复键的Map、数字等范围内映射相同的值、内存中缓存对象等,Guava提供了以上场景的解决方案。
场景 | 解决方案 | 具体实现 |
---|---|---|
多个键的Map | Table | HashBasedTable、TreeBasedTable、ImmutableTable |
不仅可以根据键获取值也可以根据值获取键且不用遍历 | BiMap | HashBiMap、ImmutableBiMap |
重复键的Map | Multimap | ArrayListMultimap、LinkedListMultimap、LinkedHashMultimap、ImmutableListMultimap、ImmutableSetMultimap |
数字等范围内映射相同的值 | RangeMap | TreeRangeMap、ImmutableRangeMap |
内存中缓存对象 | ClassToInstanceMap | MutableClassToInstanceMap、ImmutableClassToInstanceMap |
本博客将详细描述具体的示例代码。
2. 添加依赖
Maven项目pom.xml中添加依赖:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.0.0-jre</version>
</dependency>
3. Tbale - 表结构数据
官方注释翻译:将一对有序键(称为行键和列键)与单个值相关联的集合。
示例代码(需求: 记录各个公司每个部门的人数):
// HashMap
Map<String, Integer> deptMap = new HashMap<>();
deptMap.put("A部门", 10);
deptMap.put("B部门", 20);
Map<String, Map<String, Integer>> companyMap = new HashMap<>();
companyMap.put("xx公司", deptMap);
// HashMap 获取值
Integer val = companyMap.get("xx公司").get("A部门");
System.out.println("HashMap 获取值: " + val);
// 创建Hash类型Table, 基于Hash表实现
// Table<R, C, V>中三个泛型: R-行, C-列, V-值
Table<String, String, Integer> hashTable = HashBasedTable.create();
hashTable.put("xx公司", "A部门", 10);
hashTable.put("xx公司", "B部门", 20);
hashTable.put("xx公司", "C部门", 30);
System.out.println("\nHash Table: " + hashTable);
// 创建Tree类型Table, 基于红黑树实现
Table<String, String, Integer> treeTable = TreeBasedTable.create();
treeTable.put("xx公司", "C部门", 30);
treeTable.put("xx公司", "B部门", 20);
treeTable.put("xx公司", "A部门", 10);
System.out.println("\nTree Table: " + treeTable);
// 创建不可变Table, 无法新增、更新或删除
Table<String, String, Integer> immutableTable = ImmutableTable.<String, String, Integer>builder()
.put("xx公司", "C部门", 30)
.put("xx公司", "B部门", 20)
.put("xx公司", "A部门", 10)
.build();
System.out.println("\nImmutable Table: " + immutableTable);
// Table 获取值
Integer val2 = hashTable.get("xx公司", "A部门");
System.out.println("\nTable 获取值: " + val2);
// Table 删除值
Integer remove = hashTable.remove("xx公司", "C部门");
System.out.println("\nTable 删除值: " + remove);
// 根据行获取列和值映射
Map<String, Integer> columnvalueMap = hashTable.row("xx公司");
System.out.println("\nTable 列和值 映射: " + columnvalueMap);
// 根据列获取行和值映射
Map<String, Integer> rowvalueMap = hashTable.column("A部门");
System.out.println("\nTable 行和值 映射: " + rowvalueMap);
// 获取key集合
Set<String> rowKeySet = hashTable.rowKeySet();
System.out.println("\nTable Row key 集合: " + rowKeySet);
Set<String> columnKeySet = hashTable.columnKeySet();
System.out.println("\nTable Column key 集合: " + columnKeySet);
// 获取值集合
Collection<Integer> values = hashTable.values();
System.out.println("\nTable 值集合: " + values);
// 判断包含行
boolean containsRow = hashTable.containsRow("xx公司");
System.out.println("\nTable 包含行: " + containsRow);
// 判断包含列
boolean containsColumn = hashTable.containsColumn("A部门");
System.out.println("\nTable 包含列: " + containsColumn);
// 判断包含行和列
boolean contains = hashTable.contains("xx公司", "A部门");
System.out.println("\nTable 包含行和列: " + contains);
// 判断包含值
boolean containsValue = hashTable.containsValue(10);
System.out.println("\nTable 包含值: " + containsValue);
// 行和列转置 - 行 转 列
Table<String, String, Integer> transposeTable = Tables.transpose(hashTable);
// 获取所有的行
Set<Table.Cell<String, String, Integer>> cells = transposeTable.cellSet();
// 遍历输出
System.out.println("\n遍历输出开始----------------------------");
cells.forEach(cell -> System.out.println(cell.getRowKey() + ", " + cell.getColumnKey() + ", " + cell.getValue()));
System.out.println("\n遍历输出结束----------------------------");
// 转换为嵌套的Map
Map<String, Map<String, Integer>> rowMap = hashTable.rowMap();
System.out.println("\nTable RowMap: " + rowMap);
Map<String, Map<String, Integer>> columnMap = hashTable.columnMap();
System.out.println("\nTable ColumnMap: " + columnMap);
执行结果:
HashMap 获取值: 10
Hash Table: {xx公司={A部门=10, B部门=20, C部门=30}}
Tree Table: {xx公司={A部门=10, B部门=20, C部门=30}}
Immutable Table: {xx公司={C部门=30, B部门=20, A部门=10}}
Table 获取值: 10
Table 删除值: 30
Table 列和值 映射: {A部门=10, B部门=20}
Table 行和值 映射: {xx公司=10}
Table Row key 集合: [xx公司]
Table Column key 集合: [A部门, B部门]
Table 值集合: [10, 20]
Table 包含行: true
Table 包含列: true
Table 包含行和列: true
Table 包含值: true
遍历输出开始----------------------------
A部门, xx公司, 10
B部门, xx公司, 20
遍历输出结束----------------------------
Table RowMap: {xx公司={A部门=10, B部门=20}}
Table ColumnMap: {A部门={xx公司=10}, B部门={xx公司=20}}
4. BiMap - 双向映射Map
官方注释翻译:双映射(或“双向映射”)是一种保留其值及其键的唯一性的映射。此约束使双映射能够支持“反向视图”,即另一个双映射,其中包含与此双映射相同的条目,但具有相反的键和值。
示例代码(需求: 数组和英文翻译):
// 创建BiMap, 底层为两个Hash表的Map
BiMap<Integer, String> biMap = HashBiMap.create();
biMap.put(1, "one");
biMap.put(2, "two");
biMap.put(3, "three");
biMap.put(4, "four");
biMap.put(5, "five");
System.out.println("BiMap: " + biMap);
// 创建不可变BiMap, 无法新增、更新或删除
BiMap<Object, Object> immutableBiMap = ImmutableBiMap.builder()
.put(1, "one")
.put(2, "two")
.put(3, "three")
.put(4, "four")
.put(5, "five")
.build();
System.out.println("\nImmutable BiMap: " + immutableBiMap);
// 通过key获取value
String value = biMap.get(1);
System.out.println("\nBiMap 根据key获取value: " + value);
Integer key = biMap.inverse().get("one");
System.out.println("\nBiMap 根据value获取key: " + key);
// 翻转后修改
biMap.inverse().put("six", 6);
// 返回双映射的逆视图, 并没有创建新对象, 还是之前的对象, 所以操作翻转后的BiMap会影响之前的BiMap
System.out.println("\nBiMap 被影响: " + biMap);
// 底层是HashMap, key不可重复
// value不可重复
try {
biMap.put(11, "one");
} catch (Exception e) {
System.err.println("BiMap 替换value异常: " + e.getMessage());
}
// 翻转后key不能重复
try {
biMap.inverse().put("first", 1);
} catch (Exception e) {
System.err.println("BiMap 替换key异常: " + e.getMessage());
}
// key和value可为null
biMap.put(null, null);
System.out.println("\nBiMap 根据Null key获取Null value: " + biMap.get(null));
System.out.println("\nBiMap 根据Null value获取Null key: " + biMap.inverse().get(null));
// 强制替换key
biMap.forcePut(11, "one");
System.out.println("\nBiMap 获取新key: " + biMap.inverse().get("one"));
// values为Set集合
Set<String> values = biMap.values();
System.out.println("\nBiMap 不重复的value: " + values);
执行结果:
BiMap: {1=one, 2=two, 3=three, 4=four, 5=five}
Immutable BiMap: {1=one, 2=two, 3=three, 4=four, 5=five}
BiMap 根据key获取value: one
BiMap 根据value获取key: 1
BiMap 被影响: {1=one, 2=two, 3=three, 4=four, 5=five, 6=six}
BiMap 替换value异常: value already present: one
BiMap 替换key异常: key already present: 1
BiMap 根据Null key获取Null value: null
BiMap 根据Null value获取Null key: null
BiMap 获取新key: 11
BiMap 不重复的value: [two, three, four, five, six, null, one]
5. Multimap - 多重映射Map
官方注释翻译将键映射到值的集合,类似于 Map,但其中每个键可能与 多个 值相关联。
示例代码(需求: 学生和各科选修课成绩):
// 创建Multimap, key为HashMap, value为ArrayList
Multimap<String, Integer> arrayListMultimap = ArrayListMultimap.create();
arrayListMultimap.put("张三", 90);
arrayListMultimap.put("张三", 80);
arrayListMultimap.put("张三", 100);
arrayListMultimap.put("李四", 88);
System.out.println("Multimap key为HashMap, value为ArrayList: " + arrayListMultimap);
// 创建Multimap, key为HashMap, value为HashSet
Multimap<String, Integer> hashMultimap = HashMultimap.create();
hashMultimap.put("张三", 90);
hashMultimap.put("张三", 80);
hashMultimap.put("张三", 100);
hashMultimap.put("李四", 88);
System.out.println("\nMultimap key为HashMap, value为HashSet: " + hashMultimap);
// 创建Multimap, key为LinkedHashMap, value为LinkedList
Multimap<String, Integer> linkedListMultimap = LinkedListMultimap.create();
linkedListMultimap.put("张三", 90);
linkedListMultimap.put("张三", 80);
linkedListMultimap.put("张三", 100);
linkedListMultimap.put("李四", 88);
System.out.println("\nMultimap key为LinkedHashMap, value为LinkedList: " + linkedListMultimap);
// 创建Multimap, key为LinkedHashMap, value为LinkedHashMap
Multimap<String, Integer> linkedHashMultimap = LinkedHashMultimap.create();
linkedHashMultimap.put("张三", 90);
linkedHashMultimap.put("张三", 80);
linkedHashMultimap.put("张三", 100);
linkedHashMultimap.put("李四", 88);
System.out.println("\nMultimap key为LinkedHashMap, value为LinkedHashMap: " + linkedHashMultimap);
// 创建Multimap, key为TreeMap, value为TreeSet
Multimap<String, Integer> treeMultimap = TreeMultimap.create();
treeMultimap.put("张三", 90);
treeMultimap.put("张三", 80);
treeMultimap.put("张三", 100);
treeMultimap.put("李四", 88);
System.out.println("\nMultimap key为TreeMap, value为TreeSet: " + treeMultimap);
// 创建不可变Multimap, 无法新增、更新或删除, key为ImmutableMap, value为ImmutableList
Multimap<String, Integer> immutableListMultimap = ImmutableListMultimap.<String, Integer>builder()
.put("张三", 90)
.put("张三", 80)
.put("张三", 100)
.put("李四", 88)
.build();
System.out.println("\nMultimap key为ImmutableMap, value为ImmutableList: " + immutableListMultimap);
// 创建不可变Multimap, 无法新增、更新或删除, key为ImmutableMap, value为ImmutableSet
Multimap<String, Integer> immutableSetMultimap = ImmutableSetMultimap.<String, Integer>builder()
.put("张三", 90)
.put("张三", 80)
.put("张三", 100)
.put("李四", 88)
.build();
System.out.println("\nMultimap key为ImmutableMap, value为ImmutableSet: " + immutableSetMultimap);
// 获取值
Collection<Integer> values = arrayListMultimap.get("张三");
System.out.println("\nMultimap 获取值集合: " + values);
// 获取不存在key的值, 返回的是空集合, 而不是null
Collection<Integer> valuesByNotExistsKey = arrayListMultimap.get("王五");
System.out.println("\nMultimap 获取不存在的Key值集合: " + valuesByNotExistsKey);
// 获取值集合添加值
// 返回的是多重映射中关联的值的视图集合, 并没有创建新对象, 还是之前的对象, 所以操作值集合会影响之前的Multimap
values.add(60);
System.out.println("\nMultimap 被影响: " + arrayListMultimap);
// 获取大小
System.out.println("\nMultimap 大小:" + arrayListMultimap.size());
// 判断是否为空
System.out.println("\nMultimap 是否为空: " + arrayListMultimap.isEmpty());
// 包含key
System.out.println("\nMultimap 包含key: " + arrayListMultimap.containsKey("张三"));
// 包含value
System.out.println("\nMultimap 包含value: " + arrayListMultimap.containsValue(60));
// 包含key-value键值对
System.out.println("\nMultimap 包含key-value对: " + arrayListMultimap.containsEntry("张三", 60));
// 替换value
arrayListMultimap.replaceValues("张三", Arrays.asList(10, 20, 30));
System.out.println("\nMultimap 替换value: " + arrayListMultimap);
// 根据key-value删除
arrayListMultimap.remove("张三", 10);
System.out.println("\nMultimap 根据key-value删除: " + arrayListMultimap);
// 根据key删除
Collection<Integer> removeAll = arrayListMultimap.removeAll("张三");
System.out.println("\nMultimap 根据key删除: " + removeAll);
// 获取key集合
Set<String> keySet = arrayListMultimap.keySet();
System.out.println("\nMultimap 获取key集合(HashSet): " + keySet);
Multiset<String> keys = arrayListMultimap.keys();
System.out.println("\nMultimap 获取key集合(MultiSet): " + keys);
// 获取所有的key-value
Collection<Map.Entry<String, Integer>> entries = arrayListMultimap.entries();
System.out.println("\n遍历key-value开始--------------------------");
entries.forEach(entry -> System.out.println(entry.getKey() + " : " + entry.getValue()));
System.out.println("\n遍历key-value结束--------------------------");
// 转换为Map<K, Collection<V>>
Map<String, Collection<Integer>> collectionMap = arrayListMultimap.asMap();
System.out.println("\nMultimap 转换为Map<K, Collection<V>>: " + collectionMap);
执行结果:
Multimap key为HashMap, value为ArrayList: {李四=[88], 张三=[90, 80, 100]}
Multimap key为HashMap, value为HashSet: {李四=[88], 张三=[80, 100, 90]}
Multimap key为LinkedHashMap, value为LinkedList: {张三=[90, 80, 100], 李四=[88]}
Multimap key为LinkedHashMap, value为LinkedHashMap: {张三=[90, 80, 100], 李四=[88]}
Multimap key为TreeMap, value为TreeSet: {张三=[80, 90, 100], 李四=[88]}
Multimap key为ImmutableMap, value为ImmutableList: {张三=[90, 80, 100], 李四=[88]}
Multimap key为ImmutableMap, value为ImmutableSet: {张三=[90, 80, 100], 李四=[88]}
Multimap 获取值集合: [90, 80, 100]
Multimap 获取不存在的Key值集合: []
Multimap 被影响: {李四=[88], 张三=[90, 80, 100, 60]}
Multimap 大小:5
Multimap 是否为空: false
Multimap 包含key: true
Multimap 包含value: true
Multimap 包含key-value对: true
Multimap 替换value: {李四=[88], 张三=[10, 20, 30]}
Multimap 根据key-value删除: {李四=[88], 张三=[20, 30]}
Multimap 根据key删除: [20, 30]
Multimap 获取key集合(HashSet): [李四]
Multimap 获取key集合(MultiSet): [李四]
遍历key-value开始--------------------------
李四 : 88
遍历key-value结束--------------------------
Multimap 转换为Map<K, Collection<V>>: {李四=[88]}
6. RangeMap - 范围映射Map
官方注释翻译:从不相交的非空范围到非 null 值的映射。查询查找与包含指定键的范围(如果有)关联的值。
示例代码(需求:考试成绩分类):
// if-else
int score = 88;
String rank;
if (0 <= score && score < 60) {
rank = "不及格";
} else if (60 <= score && score <= 84) {
rank = "及格";
} else if (84 < score && score <= 100) {
rank = "优秀";
} else {
rank = "无效";
}
System.out.println("if-else 获取值: " + rank);
// 创建RangeMap, 基于TreeMap(红黑树)实现
RangeMap<Integer, String> treeRangeMap = TreeRangeMap.create();
treeRangeMap.put(Range.closedOpen(0, 60), "不及格");
treeRangeMap.put(Range.closed(60, 84), "及格");
treeRangeMap.put(Range.openClosed(84, 100), "优秀");
treeRangeMap.put(Range.lessThan(0), "无效");
treeRangeMap.put(Range.greaterThan(100), "无效");
rank = treeRangeMap.get(score);
System.out.println("\nRangeMap 获取值: " + rank);
// 创建不可变RangeMap, 无法新增、更新或删除
ImmutableRangeMap<Integer, String> immutableRangeMap = ImmutableRangeMap.<Integer, String>builder()
.put(Range.closedOpen(0, 60), "不及格")
.put(Range.closed(60, 84), "及格")
.put(Range.openClosed(84, 100), "优秀")
.put(Range.lessThan(0), "无效")
.put(Range.greaterThan(100), "无效")
.build();
rank = immutableRangeMap.get(score);
System.out.println("\nImmutableRangeMap 获取值: " + rank);
// 获取key-value对
Map.Entry<Range<Integer>, String> entry = treeRangeMap.getEntry(88);
System.out.println("\nRangeMap 获取key-value对: " + entry.getKey() + " : " + entry.getValue());
// 返回不可变的升序的Map
Map<Range<Integer>, String> asMapOfRanges = treeRangeMap.asMapOfRanges();
System.out.println("\nRangeMap 不可变的升序的Map: " + asMapOfRanges);
// 返回不可变的降序的Map
Map<Range<Integer>, String> asDescendingMapOfRanges = treeRangeMap.asDescendingMapOfRanges();
System.out.println("\nRangeMap 不可变的降序的Map: " + asDescendingMapOfRanges);
// 相连范围合并
RangeMap<Integer, String> treeRangeMap2 = TreeRangeMap.create();
treeRangeMap2.putCoalescing(Range.closedOpen(0, 60), "不及格");
treeRangeMap2.putCoalescing(Range.closed(60, 84), "及格");
treeRangeMap2.putCoalescing(Range.openClosed(84, 100), "及格"); // 或者 [60..84]范围合并
treeRangeMap2.putCoalescing(Range.lessThan(0), "无效");
treeRangeMap2.putCoalescing(Range.greaterThan(100), "无效");
System.out.println("\nRangeMap 不合并相连范围: " + treeRangeMap.asMapOfRanges());
System.out.println("RangeMap 合并相连范围: " + treeRangeMap2.asMapOfRanges());
// 最小范围
Range<Integer> span = treeRangeMap.span();
System.out.println("\nRangeMap 最小范围: " + span);
// 子范围Map
RangeMap<Integer, String> subRangeMap = treeRangeMap.subRangeMap(Range.closed(70, 90));
System.out.println("\nRangeMap 子范围Map: " + subRangeMap);
// 合并范围
treeRangeMap.merge(Range.closed(60, 100), "及格", (s, s2) -> s2);
System.out.println("\nRangeMap 合并Map: " + treeRangeMap);
// 移除范围
treeRangeMap.remove(Range.open(90, 95));
System.out.println("\nRangeMap 移除范围: " + treeRangeMap);
// 清除所有范围
treeRangeMap.clear();
System.out.println("\nRangeMap 清除所有范围: " + treeRangeMap);
执行结果:
if-else 获取值: 优秀
RangeMap 获取值: 优秀
ImmutableRangeMap 获取值: 优秀
RangeMap 获取key-value对: (84..100] : 优秀
RangeMap 不可变的升序的Map: {(-∞..0)=无效, [0..60)=不及格, [60..84]=及格, (84..100]=优秀, (100..+∞)=无效}
RangeMap 不可变的降序的Map: {(100..+∞)=无效, (84..100]=优秀, [60..84]=及格, [0..60)=不及格, (-∞..0)=无效}
RangeMap 不合并相连范围: {(-∞..0)=无效, [0..60)=不及格, [60..84]=及格, (84..100]=优秀, (100..+∞)=无效}
RangeMap 合并相连范围: {(-∞..0)=无效, [0..60)=不及格, [60..100]=及格, (100..+∞)=无效}
RangeMap 最小范围: (-∞..+∞)
RangeMap 子范围Map: {[70..84]=及格, (84..90]=优秀}
RangeMap 合并Map: [(-∞..0)=无效, [0..60)=不及格, [60..84]=及格, (84..100]=及格, (100..+∞)=无效]
RangeMap 移除范围: [(-∞..0)=无效, [0..60)=不及格, [60..84]=及格, (84..90]=及格, [95..100]=及格, (100..+∞)=无效]
RangeMap 清除所有范围: []
7. ClassToInstanceMap - 类型映射到实例Map
官方注释翻译:映射,其每个条目将一个 Java 原始类型 映射到该类型的实例。除了实现 Map之外,还提供额外的类型安全操作 putInstance 和 getInstance 。与任何其他 Map<Class, Object>映射一样,此映射可能包含基元类型的条目,并且基元类型及其相应的包装器类型可以映射到不同的值。
示例代码(需求:缓存Bean(不交给Spring管理,自己管理Bean)):
class UserBean {
private final Integer id;
private final String username;
public UserBean(Integer id, String username) {
this.id = id;
this.username = username;
}
@Override
public String toString() {
return "UserBean{" + "id=" + id + ", username='" + username + '\'' + '}';
}
}
// 创建Bean
UserBean userBean = new UserBean(1, "张三");
// HashMap
HashMap<Class, Object> hashMap = new HashMap<>();
hashMap.put(UserBean.class, userBean);
// 获取值,需要强转
UserBean value = (UserBean) hashMap.get(UserBean.class);
System.out.println("HashMap 获取对象实例: " + value);
System.out.println("HashMap 获取对象实例等于创建的Bean: " + (value == userBean));
// 创建ClassToInstanceMap
ClassToInstanceMap<Object> classToInstanceMap = MutableClassToInstanceMap.create();
classToInstanceMap.putInstance(UserBean.class, userBean);
// 获取值,无需强转
UserBean value2 = classToInstanceMap.getInstance(UserBean.class);
System.out.println("\nClassToInstanceMap 获取对象实例: " + value2);
System.out.println("ClassToInstanceMap 获取对象实例等于创建的Bean: " + (value2 == userBean));
// 创建不可变ClassToInstanceMap, 无法新增、更新或删除
ClassToInstanceMap<UserBean> immutableClassToInstanceMap = ImmutableClassToInstanceMap.<UserBean>builder()
.put(UserBean.class, userBean)
.build();
// 获取值,无需强转
UserBean value3 = immutableClassToInstanceMap.getInstance(UserBean.class);
System.out.println("\nImmutableClassToInstanceMap 获取对象实例: " + value3);
System.out.println("ImmutableClassToInstanceMap 获取对象实例等于创建的Bean: " + (value3 == userBean));
// 限制类型,避免使用HashMap存储对象时,因为使用Object值类型而在添加缓存时需要今天类型校验
ClassToInstanceMap<Collection> classToInstanceMap1 = MutableClassToInstanceMap.create();
classToInstanceMap1.put(ArrayList.class, new ArrayList());
classToInstanceMap1.put(HashSet.class, new HashSet());
// 编译保存: 'put(java.lang.Class<? extends [email protected] Collection>, java.util.Collection)' in 'com.google.common.collect.MutableClassToInstanceMap' cannot be applied to '(java.lang.Class<java.util.HashMap>, java.util.HashMap)'
// classToInstanceMap1.put(HashMap.class, new HashMap());
执行结果:
HashMap 获取对象实例: UserBean{id=1, username='张三'}
HashMap 获取对象实例等于创建的Bean: true
ClassToInstanceMap 获取对象实例: UserBean{id=1, username='张三'}
ClassToInstanceMap 获取对象实例等于创建的Bean: true
ImmutableClassToInstanceMap 获取对象实例: UserBean{id=1, username='张三'}
ImmutableClassToInstanceMap 获取对象实例等于创建的Bean: true
标签:Map,Multimap,ClassToInstanceMap,System,value,put,key,println,out
From: https://www.cnblogs.com/cao-lei/p/17806222.html