zoukankan      html  css  js  c++  java
  • 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/

  • 相关阅读:
    Sprint2-3.0
    6/13 Sprint2 看板和燃尽图
    6/8/9/10/11 Sprint2 看板和燃尽图
    相互观看与评价
    复利计算器结对2.0
    汉堡包1.0
    复利计算5.0 结对
    《构建之法》第四章 二人合作 读后感
    复利计算器单元测试测试报告
    实验一、命令解释程序的编写实验
  • 原文地址:https://www.cnblogs.com/moonandstar08/p/5628426.html
Copyright © 2011-2022 走看看