多值映射MultiMap
Map大概是我们在生产过程中使用最多的容器之一了。Map是一种典型的K-V(键-值)结构。即可以通过一个Key(键)查找到对应的V(值)。正是由于此,JDK规定了Map中不能有重复的键,因为重复会导致无法查询准确的值。但是我们也要注意到这么一个需求:经常地,我们会需要一个键对应多个值,如果用JDK表示,就是这种结构Map<String, List<String>>但是这种结构非常的麻烦而且相对来讲过于复杂。因此Guava为了解决这个问题为我们带来了多值映射MultiMap。
可以用两种方式思考Multimap的概念:”键-单个值映射”的集合:
a -> 1 a -> 2 a ->4 b -> 3 c -> 5
或者”键-值集合映射”的映射:
a -> [1, 2, 4] b -> 3 c -> 5
一般来说,Multimap接口应该用第一种方式看待,但asMap()视图返回Map>,让你可以按另一种方式看待Multimap。重要的是,不会有任何键映射到空集合:一个键要么至少到一个值,要么根本就不在Multimap中。
MultiMap使用实例
创建MultiMap并进行简单操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   | @Test public void testHowMultiMapWorks() {     Multimap<String, String> multimap = HashMultimap.create();     multimap.put("China", "Beijing");     multimap.put("China", "Tianjing");     multimap.put("China", "Wuhan");
      multimap.put("US", "Washington DC");     multimap.put("US", "LA");     multimap.put("US", "Seattle");     multimap.put("US", "Brooklyn");
      System.out.println("size: " + multimap.size());      System.out.println("elements list: " + multimap.get("China"));      System.out.println("keys length: " + multimap.keys().size());  }
   | 
 
迭代输出整个MultiMap
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
   | @Test public void testMultiMapAsMap() {     Multimap<String, String> multimap = HashMultimap.create();     multimap.put("US", "Washington DC");     multimap.put("US", "LA");     multimap.put("US", "Seattle");     multimap.put("US", "Brooklyn");     Map map = multimap.asMap();          Set<Map.Entry> entrySet = map.entrySet();     for (Map.Entry entry : entrySet) {         System.out.println(entry.getKey() + ":" + entry.getValue());     }      }
   | 
 
返回所有MultiMap键值对
1 2 3 4 5 6 7 8 9 10 11 12
   | @Test public void testMultiMapEntries() {     Multimap<String, String> multimap = HashMultimap.create();     multimap.put("US", "Washington DC");     multimap.put("US", "LA");     multimap.put("US", "Seattle");     multimap.put("US", "Brooklyn");     Collection collections = multimap.entries();     System.out.println(collections.toString());           }
   | 
 
获取某一个值
1 2 3 4 5 6 7 8 9 10 11
   | @Test public void testMultiMapGet() {     Multimap<String, String> multimap = HashMultimap.create();     multimap.put("US", "Washington DC");     multimap.put("US", "LA");     multimap.put("US", "Seattle");     multimap.put("US", "Brooklyn");     Collection<String> collection = multimap.get("US");     System.out.println(collection.toString());      }
   | 
 
MultiMap的各种实现
MultiMap提供了多种实现,只要你需要使用到类似于Map<String, Collection<String>>结构的数据,都可以使用MultiMap:
| 实现 | 
键行为类似 | 
值行为类似 | 
| ArrayListMultimap | 
HashMap | 
ArrayList | 
| HashMultimap | 
HashMap | 
HashSet | 
| LinkedListMultimap | 
LinkedHashMap | 
LinkedList | 
| LinkedHashMultimap | 
LinkedHashMap | 
LinkedHashMap | 
| TreeMultimap | 
TreeMap | 
TreeSet | 
| ImmutableListMultimap | 
ImmutableMap | 
ImmutableList | 
| ImmutableSetMultimap | 
ImmutableMap | 
ImmutableSet | 
 
总结
尽管Multimap的实现用到了Map,但Multimap<K, V>不是Map<K, Collection<V>>。因为两者有明显区别:
Multimap.get(key)一定返回一个非null的集合。但这不表示Multimap使用了内存来关联这些键,相反,返回的集合只是个允许添加元素的视图。 
- 如果你喜欢像
Map那样当不存在键的时候要返回null,而不是Multimap那样返回空集合的话,可以用asMap()返回的视图来得到Map<K, Collection<V>>。(这种情况下,你得把返回的Collection强转型为List或Set)。 
Multimap.containsKey(key)只有在这个键存在的时候才返回true。 
Multimap.entries()返回的是Multimap所有的键值对。但是如果需要key-collection的键值对,那就得用asMap().entrySet()。 
Multimap.size()返回的是entries的数量,而不是不重复键的数量。如果要得到不重复键的数目就得用Multimap.keySet().size()。