这里将系统的介绍 Guava
的 Map
。
在此之前请你阅读下面的博文。
所写内容
我将从下面几个方面开始讲起
集合接口
ImmutableMap
SortedMap
Multimap
BiMap
Table
ClassToInstanceMap
工具类
内容
ImmutableMap 创建 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ImmutableMap<String, Integer> immutableMap = ImmutableMap.<String, Integer>builder() .put("John" , 1000 ) .put("Jane" , 1500 ) .put("Adam" , 2000 ) .put("Tom" , 2000 ) .build(); Map<String, Integer> map = new HashMap<>() {{ put("John" , 1000 ); put("Jane" , 1500 ); put("Adam" , 2000 ); put("Tom" , 2000 ); }}; ImmutableMap<String, Integer> integerImmutableMap = ImmutableMap.copyOf(map); ImmutableMap<String,Integer> integerImmutableMap1 = ImmutableMap.of("John" ,1000 );
不可以变类初始化后,不可再更改,调用put
方法会报java.lang.UnsupportedOperationException
异常。
SortedMap 相关的函数请参考
1 2 3 4 5 6 7 ImmutableSortedMap<String, Integer> salary = new ImmutableSortedMap .Builder<String, Integer>(Ordering.natural()) .put("John" , 1000 ) .put("Jane" , 1500 ) .put("Adam" , 2000 ) .put("Tom" , 2000 ) .build();
BiMap 本节我们讨论如何使用BiMap
,BiMap
也可以反向把值映射到键,只要确保值唯一。
下面示例中,我们创建BiMap
,并使用其inverse()
方法:
1 2 3 4 5 6 7 8 9 10 @Test public void whenCreateBiMap_thenCreated () { BiMap<String, Integer> words = HashBiMap.create(); words.put("First" , 1 ); words.put("Second" , 2 ); words.put("Third" , 3 ); assertEquals(2 , words.get("Second" ).intValue()); assertEquals("Third" , words.inverse().get(3 )); }
Multimap
说个具体的应用场景吧:
比如现在我有一份日志记录,每条记录的内容是一个 url
对应一个访客的 userid
,我现在想得到 每个 url
对应的 pv
、uv
数据,你会怎么干?
普通青年一般这么想的:用 url
做 key
,userid
作为对应 list
的内容:
Map<String,List<MyClass>> myClassListMap test2 = new HashMap<String,List<MyClass>>()
然后你需要检查key
是否存在,否则创建一个,最后代码成为这个样子:
1 2 3 4 5 6 7 8 void putMyObject (String key, Object value) { List<Object> myClassList = myClassListMap.get(key); if (myClassList == null ) { myClassList = new ArrayList<object>(); myClassListMap.put(key,myClassList); } myClassList.add(value); }
如果你希望检查List
中的对象是否存在,删除一个对象,或者遍历整个数据结构,那么需要更多的代码。
看到这里不禁感叹一句:这特么都什么玩意啊。。。
恩,懒人总有懒人的办法,习惯脚本语言的我,很难忍受 java
的这种臃肿的代码了,下面看看用之前提到的 Guava MultiMap
怎么优雅的解决这个问题。
Multimap<String,Object> myMultimap = ArrayListMultimap.create();
这里需要注意,所有的guava
的集合都有create()
方法,这个好处就是比较简单,你不用重复泛型信息了。
好了,开始使用Multimap
了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 package com.test;import java.util.Collection;import com.google.common.collect.ArrayListMultimap;import com.google.common.collect.ImmutableSet;import com.google.common.collect.Multimap;public class MutliMapTest { public static void main (String... args) { Multimap<String, String> myMultimap = ArrayListMultimap.create(); myMultimap.put("Fruits" , "Bannana" ); myMultimap.put("Fruits" , "Apple" ); myMultimap.put("Fruits" , "Pear" ); myMultimap.put("Fruits" , "Pear" ); myMultimap.put("Vegetables" , "Carrot" ); int size = myMultimap.size(); System.out.println(size); Collection<String> fruits = myMultimap.get("Fruits" ); System.out.println(fruits); System.out.println(ImmutableSet.copyOf(fruits)); Collection<String> vegetables = myMultimap.get("Vegetables" ); System.out.println(vegetables); for (String value : myMultimap.values()) { System.out.println(value); } myMultimap.remove("Fruits" , "Pear" ); System.out.println(myMultimap.get("Fruits" )); myMultimap.removeAll("Fruits" ); System.out.println(myMultimap.get("Fruits" )); } }
这里有一点你可能会疑惑,就是为何get
方法返回的是一个collection
而不是list
,这是因为前者会更加有用。如果你需要基于multimap
直接操作list
或者set
,那么可以使用在定义类型的时候使用子类名称:ListMultimap
,SetMultimap
和SortedSetMultimap
。例如:
ListMutlimap<String,String> myMutlimap = ArrayListMultimap.create();
List<string> myValues = myMutlimap.get("myKey"); // Returns a List, not a Collection.
Table 当需要多余一个键索引值时,需要Table
。下面示例中,我们使用Table
存储城市之间距离:
1 2 3 4 5 6 7 8 9 10 11 12 @Test public void whenCreatingTable_thenCorrect () { Table<String,String,Integer> distance = HashBasedTable.create(); distance.put("London" , "Paris" , 340 ); distance.put("New York" , "Los Angeles" , 3940 ); distance.put("London" , "New York" , 5576 ); assertEquals(3940 , distance.get("New York" , "Los Angeles" ).intValue()); assertThat(distance.columnKeySet(), containsInAnyOrder("Paris" , "New York" , "Los Angeles" )); assertThat(distance.rowKeySet(), containsInAnyOrder("London" , "New York" )); }
ClassToInstanceMap 本节介绍ClassToInstanceMap
,把类作为键映射至对象:
1 2 3 4 5 6 7 8 9 @Test public void whenCreatingClassToInstanceMap_thenCorrect () { ClassToInstanceMap<Number> numbers = MutableClassToInstanceMap.create(); numbers.putInstance(Integer.class , 1) ; numbers.putInstance(Double.class , 1.5) ; assertEquals(1 , numbers.get(Integer.class )) ; assertEquals(1.5 , numbers.get(Double.class )) ; }
Integer
,Double
都继承子Number
,ClassToInstanceMap
让不同的子类作为key
。