一、简介
Multimap是一种将键与任意多个值相关联的通用方法。
官网对其的描述如下:
Every experienced Java programmer has, at one point or another, implemented a
Map<K, List<V>>
orMap<K, Set<V>>
, and dealt with the awkwardness of that structure. For example,Map<K, Set<V>>
is a typical way to represent an unlabeled directed graph. Guava'sMultimap
framework makes it easy to handle a mapping from keys to multiple values. AMultimap
is a general way to associate keys with arbitrarily many values.
大致意思为:咱每个有经验的程序员都基本都实现过Map<K, List<V>> 或者Map<K, Set<V>>并处理对应业务.但是这种结构很笨拙.而Guava的Multimap
会使得操作这种映射关系更容易.
有两种方法可以从概念上理解多Multimap
1、一个key对应一个值:
a -> 1
a -> 2
a -> 4
b -> 3
c -> 5
2、一个key对应一个集合
a -> [1, 2, 4]
b -> [3]
c -> [5]
通常情况下来说最好是使用第一种方式,但是也可以通过asMap的方式返回一个Map<K, List<V>> .
最重要的是,这里不会存在一个key映射到一个空集合.
在Multimap中一个key要么至少有一个值,要么就不存在.
但是我们很少直接使用Multimap接口,更多的是使用ListMultimap或者Setultimap接口,它们分别把键映射到list或者set上.
二、如何构建Multimap?
官网给的最直接的创建例子如下:它允许你如何配置表表示对应的key和value.
// creates a ListMultimap with tree keys and array list values
ListMultimap<String, Integer> treeListMultimap =
MultimapBuilder.treeKeys().arrayListValues().build();
// creates a SetMultimap with hash keys and enum set values
SetMultimap<Integer, MyEnum> hashEnumMultimap =
MultimapBuilder.hashKeys().enumSetValues(MyEnum.class).build();
也可以使用create()的方式进行创建,但是是不鼓励这样做的.部分Multimap对象创建如下:
//通过create方式创建.但是官方是不鼓励的
//通过create方式 - 创建ArrayListMultimap对象
Multimap<String, String> multimap = ArrayListMultimap.create();
//通过create方式 - 创建HashMultimap对象
Multimap<String, String> hashMultimap = HashMultimap.create();
//通过create方式 - 创建LinkedHashMultimap对象
Multimap<String, String> linkedHashMultimap = LinkedHashMultimap.create();
//通过create方式 - 创建LinkedListMultimap对象
Multimap<String, String> linkedListMultimap = LinkedListMultimap.create();
//通过create方式 - 创建TreeMultimap对象
Multimap<String, String> treeMultimap = TreeMultimap.create();
//创建ImmutableListMultimap对象
Multimap<String, String> immutableListMultimap = ImmutableListMultimap.of();
//通过create方式 - 创建TreeMultimap对象
Multimap<String, String> immutableSetMultimap = ImmutableSetMultimap.of();
三、常用方法
1、修改类型的方法 - Modifying
a、put(K, V)
方法
添加一个k - v 映射
put(K, V)
等价于multimap.get(key).add(value).
实验代码:
ListMultimap<String, Integer> treeListMultimap =
MultimapBuilder.treeKeys().arrayListValues().build();
treeListMultimap.put("ListA", 1);
treeListMultimap.put("ListA", 2);
treeListMultimap.put("ListA", 3);
//以上的put方式等价于 - xxxxMap.get().add()方式
treeListMultimap.get("ListB").add(4);
System.out.println("==================ListMultimap=====gasMap方法值====" + treeListMultimap.asMap());
输出:==================ListMultimap=====get方法值===={ListA=[1, 2, 3], ListB=[4]}
b、putAll(k, Iterable<V>)
方法
批量添加k - v数据,等同于Iterables.addAll(multimap.get(key), values)
实验代码:
//test put all - 等价于Iterables.addAll
treeListMultimap.putAll("ListC", dataList);
//等价于put all
Iterables.addAll(treeListMultimap.get("ListC"), dataList);
System.out.println("==================ListMultimap=====gasMap方法值====" + treeListMultimap.asMap());
输出:==================ListMultimap=====get方法值===={ListA=[1, 2, 3], ListB=[4], ListC=[2001, 2002, 2003, 2001, 2002, 2003]}
c、remove(k, v)
方法
从键到值删除一个关联,如果multimap改变则返回true。
等价于multimap.get(key).remove(value).
removeAll的缩小版本.
实验代码:
treeListMultimap.remove("ListA",1);
System.out.println("==================ListMultimap==remove之后===get方法值====" + treeListMultimap.get("ListA"));
输出:==================ListMultimap==remove之后===get方法值====[2, 3]
d、removeAll(K)
方法
删除并返回与指定键关联的所有值。返回的集合可以修改,也可以不修改,但是修改它不会影响multimap
实验代码:
treeListMultimap.removeAll("ListA");
System.out.println("==================ListMultimap==removeAll之后===get方法值====" + treeListMultimap.get("ListA"));
输出:==================ListMultimap==removeAll之后===get方法值====[]
e、replaceValues(k, Iterable<V>)
方法
清除与键关联的所有值,并设置与每个值关联的键。返回以前与键关联的值。
实验代码:
treeListMultimap.replaceValues("ListsB",Lists.newArrayList(101,201));
System.out.println("==================ListMultimap==replaceValues之后===get方法值====" + treeListMultimap.get("ListsB"));
输出: ==================ListMultimap==replaceValues之后===get方法值====[101, 201]
2、查询类型的方法 - Views
a、asMap()
方法
将Multimap视图以map的视图形式返回.
返回的试图支持修改,但是不支持put()以及putAll()方法.
实验的代码:
Map<String, Collection<Integer>> testAsMap = treeListMultimap.asMap();
testAsMap.remove("ListA");
System.out.println("==================测试asMap======remove方法后========="+testAsMap);
//测试put
testAsMap.put("ListD", Lists.newArrayList(301));
//测试putAll
testAsMap.putAll(Maps.newHashMap());
实验结果:
==================测试asMap======remove方法后========={ListB=[4], ListC=[2001, 2002, 2003, 2001, 2002, 2003], ListsB=[101, 201]}
java.lang.UnsupportedOperationException
at java.util.AbstractMap.put(AbstractMap.java:209)
at com.toxic.anepoch.guava.parsing.collection.newtypes.TestMultimap.main(TestMultimap.java:60)
b、entries()
方法
返回当前multiMap的映射关系.
实验代码:
System.out.println("==============测试MultiMap的entries()方法=============="+treeListMultimap.entries());
输出:==============测试MultiMap的entries()方法==============[ListB=4, ListC=2001, ListC=2002, ListC=2003, ListC=2001, ListC=2002, ListC=2003, ListsB=101, ListsB=201]
c、keySet()
返回当前MultiMap的key - set集合
实验代码:
System.out.println("==============测试MultiMap的keySet()方法=============="+treeListMultimap.keySet());
输出:==============测试MultiMap的keySet()方法==============[ListB, ListC, ListsB]
d、keys()
返回当前MultiMap的MultiSet视图
实验代码:
System.out.println("==============测试MultiMap的keys()方法=============="+treeListMultimap.keys());
输出:==============测试MultiMap的keys()方法==============[ListB, ListC x 6, ListsB x 2]
e、values()
返回当前MultiMap拍平了的value - collection集合
实验代码:
System.out.println("==============测试MultiMap的values()方法=============="+treeListMultimap.values());
输出:==============测试MultiMap的values()方法==============[4, 2001, 2002, 2003, 2001, 2002, 2003, 101, 201]
四、最后值得注意的是MultiMap并不是一个map
感兴趣的可以了解一下
官网描述:
A
Multimap<K, V>
is not aMap<K, Collection<V>>
, though such a map might be used in aMultimap
implementation. Notable differences include:
-
Multimap.get(key)
always returns a non-null, possibly empty collection. This doesn't imply that the multimap spends any memory associated with the key, but instead, the returned collection is a view that allows you to add associations with the key if you like. - If you prefer the more
Map
-like behavior of returningnull
for keys that aren't in the multimap, use theasMap()
view to get aMap<K, Collection<V>>
. (Or, to get aMap<K,
List
<V>>
from aListMultimap
, use the staticMultimaps.asMap()
method. Similar methods exist forSetMultimap
andSortedSetMultimap
.) -
Multimap.containsKey(key)
is true if and only if there are any elements associated with the specified key. In particular, if a keyk
was previously associated with one or more values which have since been removed from the multimap,Multimap.containsKey(k)
will return false. -
Multimap.entries()
returns all entries for all keys in theMultimap
. If you want all key-collection entries, useasMap().entrySet()
. -
Multimap.size()
returns the number of entries in the entire multimap, not the number of distinct keys. UseMultimap.keySet().size()
instead to get the number of distinct keys.
......未完待续