MultiMap、BidiMap及LazyMap的使用

一、MultiMap

  在日常的开发工作中,我们有的时候需要构造像Map<K, List<V>>或者Map<K, Set<V>>这样比较复杂的集合类型的数据结构,以便做相应的业务逻辑处理。

  但是像Map<String, List<StudentScore>> StudentScoreMap = new HashMap<String, List<StudentScore>>()这样的数据结构,自己实现起来太麻烦,你需要检查key是否存在,不存在时则创建一个,存在时在List后面添加上一个。这个过程是比较痛苦的,如果你希望检查List中的对象是否存在,删除一个对象,或者遍历整个数据结构,那么则需要更多的代码来实现。

   Guava的Multimap就提供了一个方便地把一个键对应到多个值的数据结构。让我们可以简单优雅的实现上面复杂的数据结构,让我们的精力和时间放在实现业务逻辑上,而不是在数据结构上,下面我们具体来看看Multimap的相关知识点。

  上面的代码和数据结构用Multimap来实现,代码结构清晰简单了很多吧,具体代码如下:

 /**** 
  * 所谓MultiMap,就是说一个key不在是简单的指向一个对象,而是一组对象, 
  * add()和remove()的时候跟普通的Map无异,只是在get()时返回一个Collection, 
  * 利用MultiMap,我们就可以很方便的往一个key上放数量不定的对象,也就实现了一对多。 
  */ 

public class MutliMapTest {
    public static void main(String... args) {
     Multimap<String, String> myMultimap = ArrayListMultimap.create();
  
     // Adding some key/value
     myMultimap.put("Fruits", "Bannana");
     myMultimap.put("Fruits", "Apple");
     myMultimap.put("Fruits", "Pear");
     myMultimap.put("Vegetables", "Carrot");
  
     // Getting the size
     int size = myMultimap.size();
     System.out.println(size);  // 4
  
    // Getting values
    Collection<string> fruits = myMultimap.get("Fruits");
    System.out.println(fruits); // [Bannana, Apple, Pear]
  
    Collection<string> vegetables = myMultimap.get("Vegetables");
    System.out.println(vegetables); // [Carrot]
  
    // Iterating over entire Mutlimap
    for(String value : myMultimap.values()) {
     System.out.println(value);
    }
  
    // Removing a single value
    myMultimap.remove("Fruits","Pear");
    System.out.println(myMultimap.get("Fruits")); // [Bannana, Pear]
    
    // Remove all values for a key
    myMultimap.removeAll("Fruits");
   System.out.println(myMultimap.get("Fruits")); // [] (Empty Collection!)


    List<String> list = new ArrayList<String>();  
    List<String> valuelist = new ArrayList<String>();  
    list.add("123");  
    list.add("456");  
   list.add("789");  
   MultiMap multiMap = new MultiHashMap();  
   multiMap.put("Sean", list);  
   multiMap.put("Sean", "C/C++");  
   multiMap.put("Sean", "OO");  
   multiMap.put("Sean", "Java");  
   multiMap.put("Sean", ".NET");  
   multiMap.remove("Sean", "C/C++");  
   System.out.println("Sean's skill set: " + multiMap.get("Sean"));  
  Iterator itet = ((Collection) multiMap.get("Sean")).iterator();  
  while(itet.hasNext())  
  {  
    Object obj = itet.next();  
    if(obj instanceof List)  
   {  
     valuelist = (List<String>)obj;  
     for(Object value:valuelist)  
    {  
      System.out.println("obj1:"+value);
     }             
    }else if(obj instanceof String)  
    {  
     System.out.println("value:"+obj.toString());  
    }  
 }  
  
  }
}

 Multimap也支持一系列强大的视图功能:   

 1、asMap把自身Multimap<K, V>映射成Map<K, Collection<V>>视图。这个Map视图支持remove和修改操作,但是不支持put和putAll。严格地来讲,当你希望传入参数是不存在的key,而且你希望返回的是null而不是一个空的可修改的集合的时候就可以调用asMap().get(key)。(你可以强制转型asMap().get(key)的结果类型-对SetMultimap的结果转成Set,对ListMultimap的结果转成List型-但是直接把ListMultimap转成Map<K, List<V>>是不行的。)   

2、entries视图是把Multimap里所有的键值对以Collection<Map.Entry<K, V>>的形式展现。   

3、keySet视图是把Multimap的键集合作为视图   

4、keys视图返回的是个Multiset,这个Multiset是以不重复的键对应的个数作为视图。这个Multiset可以通过支持移除操作而不是添加操作来修改Multimap。   

5、values()视图能把Multimap里的所有值“平展”成一个Collection<V>。这个操作和Iterables.concat(multimap.asMap().values())很相似,只是它返回的是一个完整的Collection。

 尽管Multimap的实现用到了Map,但Multimap<K, V>不是Map<K, Collection<V>>。因为两者有明显区别:   1.Multimap.get(key)一定返回一个非null的集合。但这不表示Multimap使用了内存来关联这些键,相反,返回的集合只是个允许添加元素的视图。   2.如果你喜欢像Map那样当不存在键的时候要返回null,而不是Multimap那样返回空集合的话,可以用asMap()返回的视图来得到Map<K, Collection<V>>。(这种情况下,你得把返回的Collection<V>强转型为List或Set)。   3.Multimap.containsKey(key)只有在这个键存在的时候才返回true。   4.Multimap.entries()返回的是Multimap所有的键值对。但是如果需要key-collection的键值对,那就得用asMap().entries()。   5.Multimap.size()返回的是entries的数量,而不是不重复键的数量。如果要得到不重复键的数目就得用Multimap.keySet().size()。

注:MultiMap是非线程安全的,转化为线程这全对象时可以参考:

      private ListMultimap<Long,Long> map = ArrayListMultimap.create();

      private Multimap<Long,Long> syncMap = Multimaps.synchronizedMultimap(map);

二、BidiMap

/**** 
  * 所谓BidiMap,直译就是双向Map,可以通过key找到value, 
  * 也可以通过value找到key,这在我们日常的代码-名称匹配的时候很方便: 
  * 因为我们除了需要通过代码找到名称之外,往往也需要处理用户输入的名称,然后获取其代码。 
  * 需要注意的是BidiMap当中不光key不能重复,value也不可以。 
  */  
    public static void demoBidiMap() {   
         System.out.println(StringUtils.center(" demoBidiMap ", 40, "="));    
         BidiMap bidiMap = new DualHashBidiMap();    
         bidiMap.put("BJ", "Beijing");    
         bidiMap.put("SH", "Shanghai");    
         bidiMap.put("GZ", "Guangzhou");    
         bidiMap.put("CD", "Chengdu");    
         System.out.println("Key-Value: BJ = " + bidiMap.get("BJ"));    
         System.out.println("Value-Key: Chengdu = " + bidiMap.getKey("Chengdu"));    
         System.out.println(StringUtils.repeat("=", 40));   
 }  

 

三、LazyMap

/**所谓LazyMap,意思就是这个Map中的键/值对一开始并不存在,当被调用到时才创建. 
 * 我们这样来理解:我们需要一个Map,但是由于创建成员的方法很“重”(比如数据库访问), 
 * 或者我们只有在调用get()时才知道如何创建,或者Map中出现的可能性很多很多, 
 * 我们无法在get()之前添加所有可能出现的键/值对, 
 * 我们觉得没有必要去初始化一个Map而又希望它可以在必要时自动处理数据 
 * 
 */  
 @SuppressWarnings(value = {"unchecked"})  
 public static void demoLazyMap()  
{  
       System.out.println(StringUtils.center(" demoLazyMap ", 40, "="));  
       Factory factory = new Factory() {  
       public Object create() {  
               return new Date();  
       }  
  };  
      Map lazy = LazyMap.decorate(new HashMap(), factory);  
      System.out.println("map:"+lazy);//lazy为空  
      System.out.println(lazy.get("123"));  
      System.out.println(lazy.get("345"));  
      System.out.println(StringUtils.repeat("=", 40));  
  }  

四、其它

其它链接请参见:http://ifeve.com/google-guava-newcollectiontypes/

原文地址:https://www.cnblogs.com/moonandstar08/p/5628426.html